home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DS-CD ROM 2 1993 August
/
DS CD-ROM 2.Ausgabe (August 1993).iso
/
programm
/
ds0256
/
mdebug22.exe
/
DRIVER.PRT
< prev
next >
Wrap
Text File
|
1992-11-21
|
152KB
|
4,441 lines
───────────────────────────────────────────────────────────────────
MDEBUG
Version V2.05
Highperformance Debugging Tool für PCs
Dokumentation für die Kommando- und Bildschirmtreiber
von MDEBUG
Copyright 1992 by
Bernd Schemmer
All Rights reserved.
───────────────────────────────────────────────────────────────────
Credits
MDEBUG wurde geschrieben von Bernd Schemmer.
Die Kommandotreiber MDDISDRV, MDHISDRV und MDBSPDRV und die Bild-
schirmtreiber MDHGCDRV und MDCGADRV wurden geschrieben von Bernd
Schemmer.
───────────────────────────────────────────────────────────────────
Copyright
MDEBUG ist Copyright 1992 by Bernd Schemmer
Alle Bildschirm- und Kommandotreiber auf dieser Diskette sind
Copyright 1992 by Bernd Schemer
Dieses Dokument ist Copyright 1992 by Bernd Schemmer
───────────────────────────────────────────────────────────────────
Eingetragene Warenzeichen, Warennamen
Warenamen und eingetragene Warenzeichen werden in diesem Text ohne
Gewährleistung einer freien Verwendung benutzt.
Alle benutzten Warenanamen und eingetragenen Warenzeichen sind
Eigentum ihrer jeweiligen Besitzer.
───────────────────────────────────────────────────────────────────
Granatie-Ausschluß-Erklärung
Bernd Schemmer gibt keine Garantien irgendeiner Art, weder aus-
drücklich noch implizit, einschliesslich unbegrenzt aller Garantien
der Verwendbarkeit und/oder Nichtverwendbarkeit für irgendeinen
Zweck. Bernd Schemmer übernimmt keine Verpflichtungen für den
Gebrauchswert dieser Software über den Kaufpreis dieser Software
hinaus. Unter keinen Umständen ist Bernd Schemmer haftbar für
jedwede Folgeschäden, einschliesslich aller entgangenen Gewinne und
Vermögensverluste, oder anderer mittelbarer und unmittelbarer
Schäden, die durch den Gebrauch oder die Nichtverwendbarkeit
dieser Software und ihrer begleitenden Dokumentation entstehen.
Dies gilt auch dann, wenn Bernd Schemmer über die Möglichkeit
solcher Schäden unterrichtet war oder ist.
───────────────────────────────────────────────────────────────────
Inhalt Seite
────────────────────────────────────────────────────────────
Einleitung ........................................... 1
Allgemeine Parameter für die Treiber ................. 2
/Pnn - Festlegen der Prozessnummer des Treibers .... 2
/I - Ändern der Voreinstellungen ................... 2
/R - Freigabe des Treibers ......................... 3
/? - Ausgabe der Aufrufsyntax ...................... 3
@ - Kommentareinleitung ............................ 4
Syntax der Parameter ................................. 4
MDCGADRV.COM ......................................... 5
MDHGCDRV.COM ......................................... 6
MDHISDRV.COM ......................................... 7
Parameter für MDHISDRV ............................. 7
/H{1|0} - Benutzung der UMBs einstellen .......... 7
/Bnn - festlegen der Puffergröße ............... 7
Funktionen für den Interpreter ..................... 7
Tastenbelegung im Interpreter ...................... 8
Befehle für den Interpreter ........................ 9
Einrichten von Macro-Befehlen ...................... 13
MDDISDRV.COM ......................................... 14
Installieren des Disassemblers ..................... 14
Parameter für MDDISDRV ............................. 14
/Dn,m - Drucker ändern ........................... 14
/Lnn - Startzeile ändern ......................... 15
/Fn{,}mm - Farben ändern ......................... 15
/Assss:oooo - Start-Adresse ändern .............. 16
/Sswitches - Schalter ändern ..................... 16
/H{1|0} - Benutzung der UMBs einstellen .......... 18
*{!}name - Sichern des Status des Disassemblers .. 18
&name - Laden des Status des Disassemblers ....... 19
/Qn - Quiet-Modus ein/ausschalten ................ 19
# - Ausgabe der Codes der Funktionstasten ........ 19
Aufruf des Disassemblers in MDEBUG ................. 20
Aufruf des Disassemblers im Monitor von MDEBUG ..... 20
Aufruf des Disassemblers im Interpreter von MDEBUG . 20
Aufruf des Disassemblers durch Befehle in MDEBUG ... 21
Weitere Befehle des Disassemblers für MDEBUG ....... 21
Bedienung des Disassemblers ........................ 22
────────────────────────────────────────────────────────────────────────────────
Inhalts-Verzeichnis I 1
Inhalt Seite
────────────────────────────────────────────────────────────
Aufbau der Windows ............................... 22
Aufbau des Windows im Disassembler-Modus ......... 22
Aufbau des Windows im Assembler-Modus ............ 27
Aufbau des Windows im Dump-Modus ................. 28
Tastenbelegung des Disassemblers ................. 30
Suchen von Referenzen ............................ 35
Benutzung des Adressen-Stacks .................... 36
Die Funktion 'Folge dem Befehl' .................. 37
Die Schalter des Disassemblers ..................... 40
Anzeige-Modi für Offsets und Displacements ....... 40
Der Schalter B ................................... 41
Der Schalter P ................................... 41
Der Schalter U ................................... 42
Der Schalter R ................................... 42
Der Schalter W ................................... 42
Der Schalter A ................................... 42
Der Schalter F ................................... 42
Der Schalter L ................................... 43
Der Schalter K ................................... 44
Der Schalter Q ................................... 44
Sichern von Speicherbereichen ...................... 45
Allgemeines zum Sichern von Speicherbereichen .... 45
Sichern von Speicherbereichen in eine Datei ...... 47
Erstellen von Quelldateien für den A86 ........... 48
Ausgabe von Speicherbereichen auf den Drucker .... 50
Zusammenfassung der Tastenbelegung im Disassembler . 51
Syntax für die Anzeige der Befehle ................. 54
Mnemonics für die Opcodes des 80386 .............. 55
Ausgabe von ESC-Befehlen ......................... 56
Behandlung von unbekannten Opcodes ............... 57
Opcodes mit unmöglichen Operanden ................ 58
Format von expliziten Werten ..................... 59
Format von Speicheroperanden ..................... 59
MDBSPDRV.COM ......................................... 60
Befehle für den Interpreter ........................ 60
Tastenbelegung im Monitor .......................... 62
Tastenbelegung im Interpreter ...................... 63
────────────────────────────────────────────────────────────────────────────────
Inhalts-Verzeichnis I 2
Inhalt Seite
────────────────────────────────────────────────────────────
Programm-Interna der Treiber ......................... 64
Errorlevel der Treiber ............................... 65
Fehlermeldungen des transienten Teils der Treiber .... 66
────────────────────────────────────────────────────────────────────────────────
Inhalts-Verzeichnis I 3
Einleitung
──────────
Diese Datei enthält die Beschreibungen der zusätzlich zu MDEBUG
mitgelieferten Bildschirm- und Kommandotreiber.
Im einzelnen sind dies die Bildschirmtreiber
MDCGADRV - Bildschirmtreiber für eine CGA-Karte
MDHGCDRV - Bildschirmtreiber für eine HGC-Karte
und die Kommandotreiber
MDHISDRV - Kommandotreiber mit einer Historyfunktion für MDEBUG
MDDISDRV - Kommandotreiber mit einem Disassembler für MDEBUG
MDBSPDRV - Kommandotreiber mit verschiedenen neuen Tasten-
belegungen und Interpreter-Befehlen für MDEBUG.
Da verschiedene Aspekte (mehrere Parameter, Syntax der Parameter,
Interna, Errorlevel und mehrere Fehlermeldungen des transienten
Teils der Treiber) bei allen Treibern gleich sind, sind diese
Informationen nur einmal angeführt.
────────────────────────────────────────────────────────────────────────────────
Seite 1
Allgemeine Parameter für die Treiber
────────────────────────────────────
Hinweis: Alle Angaben in geschweiften Klammern ( {..} ) in den
folgenden Beschreibungen sind optional.
Die folgenden Parameter sind bei allen Treibern möglich:
{/Pnn} {/I} {/R} {{/}?} {@ kommentar}
Beschreibung der Parameter:
/Pnn - Festlegen der Prozessnummer des Treibers
Mit dem Parameter '/Pnn' kann die Prozessnummer des Treibers für
die Kommunikation mit MDEBUG festgelegt werden. MDEBUG kommuni-
ziert mit den Treibern über den Multiplex-Interrupt 2Fh und der
angegebenen Prozessnummer.
'nn' muß ein hexadezimaler Wert zwischen 0C0h und 0FEh (für Bild-
schirmtreiber) oder 0C1h und 0FFh (für Kommandotreiber) sein.
Voreinstellung für 'nn' ist bei Bildschirmtreibern 0D0h und bei
Kommandotreibern 0D1h. Die Prozessnummer muß mit der von MDEBUG
verwendeten Prozessnummer übereinstimmen!
/I - Ändern der Voreinstellungen
Durch den Parameter '/I' kann eine neue Version eines Treibers
erstellt werden.
Alle zusätzlich zu diesem Parameter angegebenen Parameter (vor
oder hinter dem Parameter '/I') werden als neue Voreinstellungen
in die neue Version des Treibers eingetragen.
Der Parameter '/R' wird dabei ignoriert.
Die neue Version des Treibers wird immer im aktuellem Directory
erstellt. Falls dort schon eine Datei mit dem Namen des Treibers
existiert, wird deren Extension in '.BAK' geändert. Eine evtl.
schon vorhandene Datei mit den Namen des Treibers und der Exten-
sion '.BAK' wird in jedem Fall gelöscht.
Bei der Erstellung der neuen Version werden alle Fehler (incl.
Hardware-Fehler) abgefangen. Eine nur teilweise geschriebene
Datei wird aber nicht gelöscht.
────────────────────────────────────────────────────────────────────────────────
Seite 2
Nach der Bearbeitung des Parameters '/I' wird das Programm sofort
beendet.
Beispiel:
MDCGADRV /I /PD4
Erstellt eine neue Version des Treibers MDCGADRV.COM bei der als
Voreinstellung für die Prozessnummer 0D4h vorgesehen ist.
Beim Aufruf der neuen Version des Treibers können die geänderten
Voreinstellungen aber selbstverständlich wieder durch Parameter
überschrieben werden.
Hinweis:
Im Gegensatz zum Parameter 'MAKE' von MDEBUG ist der Parameter
'/I' der Treiber auch schon in der Shareware-Version möglich.
/R - Freigabe des Treibers
Durch den Aufruf eines Treibers mit den Parameter '/R' kann eine
residente Version des Treibers wieder aus dem Speicher entfernt
werden.
Vorraussetzung dafür ist, daß der Treiber das letzte Programm in
der Kette für den Interrupt 2Fh (und evtl. zusätzlich belegter
Interrupts) ist. Ist dies nicht der Fall, wird nur eine Fehler-
meldung ausgegeben und der Treiber nicht aus dem Speicher ent-
fernt.
/? - Ausgabe der Aufrufsyntax
Die Angabe des Parameters '/?' oder '?' veranlasst die Treiber
zur Ausgabe eines Hilfstextes mit der Syntax für den Aufruf und
den Voreinstellungen für die Parameter.
Falls der Treiber über den Parameter '/I' neu konfiguriert wurde,
werden im Hilfstext selbstverständlich die geänderten Voreinstel-
lungen angezeigt.
Eventuell zusätzlich zu diesem Parameter angegebene Parameter
werden im Hilfstext als Voreinstellungen für die Parameter aus-
gegeben. D.h. die eigentlichen Voreinstellungen der Parameter
werden durch die Angaben überschrieben. Nach der Ausgabe des
Hilfstextes wird das Programm sofort beendet.
Der Parameter '?' hat die höchste Priorität aller Parameter.
────────────────────────────────────────────────────────────────────────────────
Seite 3
@ - Kommentareinleitung
Der Parameter '@' leitet Kommentare ein, d.h. alle weiteren Para-
meter werden von den Treibern ignoriert. Das bedeutet auch, daß
das Zeichen '@' in keinem anderen Parameter vorkommen darf!
Der Parameter dient hauptsächlich zur Einfügung von Kommentaren
in Batch-Dateien.
Syntax der Parameter
────────────────────
Alle Parameter sind optional.
Die Parameter können in beliebiger Reihenfolge angegeben werden;
Groß- und Kleinschreibung ist ebenfalls beliebig.
Als Trennzeichen für die Parameter können die Zeichen '/' und '-'
verwendet werden. Die Parameter sollten zusätzlich durch min-
destens ein Leerzeichen oder Tabulatorzeichen getrennt werden.
Bei mehrmals angegebenen oder sich ausschließenden Parametern
wird der zuletzt angegebene Parameter benutzt.
Fehlerhafte Parameter führen zur Ausgabe einer Fehlermeldung und
zum Abbruch der Programmausführung.
Alle Parameter, mit Ausnahme des Parameters '/R', werden, falls
nichts anderes angegeben ist, nur beim Aufruf zum Installieren
der Treiber berücksichtigt.
Bei der Deinstallation werden alle zusätzlich zum Parameter '/R'
angegebenen Parameter nur auf die Syntax überprüft aber nicht
weiter bearbeitet.
Jeder Treiber kann vor oder nach MDEBUG geladen werden, falls er
deinstalliert werden soll muß er das letzte Programm in der
Kette für den Interrupt 2Fh (und evtl. weiterer belegter Inter-
rupts) sein.
────────────────────────────────────────────────────────────────────────────────
Seite 4
MDCGADRV.COM
────────────
MDCGADRV.COM ist ein Bildschirmtreiber für MDEBUG. MDCGADRV.COM
erlaubt den Aufruf von MDEBUG auch in den Graphik-Modi und den
Modi mit 40 Zeichen pro Zeile einer CGA-Karte.
Aufruf: MDCGADRV {/Pnn} {/I} {/R} {/?} {@...}
Parameter: (siehe 'Allgemeine Parameter für die Treiber')
Falls der Treiber geladen ist, kann MDEBUG in allen Modi der
normalen CGA-Karte (also auch im Graphik-Modus und in den Modi
mit 40 Zeichen pro Zeile) aufgerufen werden.
Der Treiber verwendet fast ausschließlich Aufrufe des Interrupt
10h zum Ermitteln und Setzen der Bildschirmmodi.
Ausnahme:
Der Inhalt der Register 03D8h und 03D9h wird direkt aus der BIOS-
Data-Area ermittelt und direkt über OUT-Befehle gesetzt.
Auf manchen CGA-Karten verbusselt der Treiber die Bedeutung des
7. Bits (Intensity- oder Blink-Bit) oder ändert die Farbpalette.
Der Grund dieses Fehlers ist mir noch nich bekannt, Besitzer der
Vollversion können dieses Manko aber speziell für ihre CGA-Karte
im Quelltext des Treibers beseitigen.
Bei älteren Spielen und Programmen, die direkt die CGA-Karte
programmieren, versagt der Treiber.
────────────────────────────────────────────────────────────────────────────────
Seite 5
MDHGCDRV.COM
────────────
MDHGCDRV.COM ist ein Bildschirmtreiber für MDEBUG. MDHGCDRV.COM
erlaubt den Aufruf von MDEBUG auch im Graphikmodus der Hercules-
Karte.
Aufruf: MDHGCDRV {/Pnn} {/I} {/R} {/?} {@...}
Parameter: (siehe 'Allgemeine Parameter für die Treiber')
Falls der Treiber geladen ist, kann MDEBUG in allen Modi der
normalen HGC-Karte aufgerufen werden.
Der Treiber überprüft den aktuellen Modus der Karte über das
Lightpen-Register. Der Graphikmodus und der Textmodus werden
durch direkte Programmierung der Register 3B4h, 3B5h, 3B8h, 3B9h
und 3BFh des CRT-Controllers eingeschaltet.
Die Register des CRT-Controllers werden vom Treiber für die
beiden Modi folgendermaßen programmiert:
┌──────────┬─────────┬──────┐ ┌──────────┬─────────┬───────┐
│Controller│ Graphik │ Text │ │ │ Graphik │ Text │
│Register │ Mode │ Mode │ │ Register │ Mode │ Mode │
╞══════════╪═════════╪══════╡ ╞══════════╪═════════╪═══════╡
│ 00h │ 36h │ 61h │ │ 03B8h │ 29h │ 0Ah │
│ 01h │ 2Dh │ 50h │ ├──────────┼─────────┼───────┤
│ 02h │ 2Fh │ 52h │ │ 03B9h │ 30h │ 30h │
│ 03h │ 07h │ 0Fh │ ├──────────┼─────────┼───────┤
│ 04h │ 5Bh │ 19h │ │ 03BFh │ 00h │ 03h │
│ 05h │ 00h │ 06h │ └──────────┴─────────┴───────┘
│ 06h │ 57h │ 19h │
│ 07h │ 57h │ 19h │ Die Angaben wurde der Dokumentation
│ 08h │ 02h │ 02h │ zur Graphik-Karte 'ATI-Solution 1'
│ 09h │ 03h │ 0Dh │ entnommen. Es kann sein, daß diese
│ 0Ah │ 00h │ 0Bh │ Werte nicht mit denen von anderen
│ 0Bh │ 00h │ 0Ch │ HGC-Karten übereinstimmen. Besitzer
│ 0Ch │ 00h │ 00h │ der Vollversion können diese aber
│ 0Dh │ 00h │ 00h │ im Quellcode des Treibers korri-
└──────────┴─────────┴──────┘ gieren.
Hinweis:
Bei älteren Spielen und Programmen, die direkt die HGC-Karte
programmieren, versagt der Treiber.
────────────────────────────────────────────────────────────────────────────────
Seite 6
MDHISDRV.COM
────────────
MDHISDRV.COM ist ein Kommandotreiber für MDEBUG. MDHISDRV.COM
stellt eine History-Funktion für MDEBUG zur Verfügung.
Aufruf: MDHISDRV {/H{1|0}} {/Bnn} {/Pnn} {/I} {/R} {/?} {@...}
Parameter für MDHISDRV
(siehe auch 'Allgemeine Parameter für die Treiber')
/H{1|0} - Benutzung der UMBs einstellen
Mit diesem Parameter kann festgelegt werden, ob der residente
Teil von MDHISDRV in einen Speicherbereich oberhalb von A000h
verschoben werden soll (n = 1) oder nicht (n = 0). Voreinstellung
für n ist 0. Falls der Parameter in der Form '/H' angegeben wird,
wird der aktuelle Wert von n umgeschaltet. Falls der Parameter
'/H1' angegeben wird, und kein freier Speicherbereich in der
benötigten Größe oberhalb von A000h vorhanden ist (z.B. bei DOS-
Versionen vor 5.00 ohne speziellen Speichermanager oder falls
alle Blöcke oberhalb von A000h schon belegt sind), wird der
residente Teil von MDHISDRV im Speicherbereich unterhalb von
A000h belassen.
Der Parameter wird nur bei der Installation des Treibers berück-
sichtigt.
/Bnn - festlegen der Puffergröße
'nn' ist die Größe des Puffers für die History-Funktion in Byte
(dez., Intervall: 128..max, Voreinst.: 512)
Der maximal mögliche Wert für diesen Parameter ergibt sich aus
der Größe des freien Speichers bei der Installation des Treibers.
(maximal ca. 60.000)
Funktionen für den Interpreter
──────────────────────────────
Der Treiber stellt eine History-Funktion für den Interpreter von
MDEBUG zur Verfügung, d.h. nach dem MDHISDRV geladen ist können
die letzten Befehlszeilen jeweils aus einem Puffer restauriert
werden. Die Anzahl der Befehlszeilen, die restauriert werden
können, richtet sich nach der Größe des eingerichteten Puffers
und nach der Länge der Befehlszeilen. Der Puffer zum Speichern
der Befehlszeilen ist als Ringpuffer organisiert, d.h. falls der
Puffer voll ist werden die Befehlszeilen am Anfang des Puffers
mit den nächsten Befehlszeilen überschrieben.
────────────────────────────────────────────────────────────────────────────────
Seite 7
Tastenbelegung im Interpreter
─────────────────────────────
Der Treiber sichert alle Befehlszeilen, die mit <RETURN> abge-
schlossen wurden. Befehlszeilen, die mit <ALT-RETURN> beendet
wurden, werden nicht gesichert. Eingaben, die über <CTRL-RETURN>
nochmals bearbeitet wurden, werden kein zweitesmal gespeichert.
Es werden nur Befehlszeilen mit mehr als einem Zeichen gesichert
(wobei Leerzeichen nicht zählen).
Zur Verwaltung des Puffers belegt der Treiber folgende Tasten im
Interpreter:
<CTRL-R> - History-Funktion einschalten
Der Treiber sichert die Befehlszeilen nur, falls er eingeschaltet
ist. (Voreinstellung)
<CTRL-V> - History-Funktion ausschalten
Die Befehlszeilen werden nicht mehr gesichert. (bis zum nächsten
Einschalten der History-Funktion) Das Restaurieren von Befehls-
zeilen über die Tasten <CTRL-E> und <CTRL-X> funktioniert aber
auch bei ausgeschalteter History-Funktion.
<CTRL-E>
<CTRL-X> - Mit diesen Tasten kann eine gesicherte Befehlszeile
aus dem Puffer gewählt werden.
Hinweis:
Der letzte Befehl muß entweder über die Taste <SHIFT-RETURN>
oder über die Tastenfolge <CTRL-E><CTRL-X> restauriert werden.
Der Treiber gibt einen Fehlerton aus falls es keinen vorherigen
oder nächsten Befehl im Puffer mehr gibt. Falls der Treiber einen
Fehler in der Pufferverwaltung feststellt, wird der gesamte
Puffer gelöscht. (z.B. nach dem Laden einer neuen Datei, s.u.)
Befehlszeilen, die über die Tasten <CTRL-E> und <CTRL-X> restau-
riert wurden, werden kein zweitesmal gesichert (falls sie nicht
vor der erneuten Ausführung editiert werden).
<CTRL-D> - gesamten Puffer der History-Funktion löschen
Der Puffer wird nur gelöscht, falls die History-Funktion ein-
geschaltet ist.
────────────────────────────────────────────────────────────────────────────────
Seite 8
Zusätzlich stellt der Treiber MDHISDRV noch 10 Einzelpuffer für
jeweils eine Befehlszeile zur Verfügung.
Die Befehlszeilen in den Einzelpuffern können über die folgenden
Tasten ausgeführt werden:
<ALT><0> (Tastencode: 8100h) -- Einzelpuffer 0
<ALT><1> (Tastencode: 7800h) -- Einzelpuffer 1
<ALT><2> (Tastencode: 7900h) -- Einzelpuffer 2
...
<ALT><9> (Tastencode: 8000h) -- Einzelpuffer 9
Die Befehlszeile wird sofort ausgeführt! Falls die sofortige
Ausführung verhindert werden soll, kann als erster Befehl in der
Befehlszeile ein ungültiger Befehlsname angegeben werden.
<0> bis <9> sind die Ziffern aus der obersten Reihe der Tastatur.
Falls der gewählte Einzelpuffer leer ist, gibt der Treiber die
Taste an den nächsten Treiber weiter bzw. an MDEBUG zurück.
Befehle für den Interpreter
───────────────────────────
Zusätzlich stellt der Treiber folgende neue Befehle zur Verfügung
(signifikant ist jeweils nur das erste und das letzte Zeichen der
Befehle):
W{RITE}B {dateiname}
Dieser Befehl schreibt den Inhalt und die Daten des Puffers der
History-Funktion und die Inhalte der Einzelpuffer (s.u.) in die
Datei 'dateiname'. Eine schon existierende Datei wird dabei ohne
Warnung überschrieben.
Die Voreinstellung für den Dateinamen ist 'MDHISDRV.BUF'.
R{EAD}B {dateiname}
Der Befehl RB liest den Inhalt und die Daten des Puffers der
History-Funktion und die Inhalte der Einzelpuffer (s.u.) aus der
Datei 'dateiname'. Falls ein Fehler auftritt, werden der Puffer
der History-Funktion und die Einzelpuffer gelöscht.
────────────────────────────────────────────────────────────────────────────────
Seite 9
Falls die angegebene Datei größer als der vorhandene Puffer ist,
wird nur der erste Teil der Datei gelesen (die Einzelpuffer
werden immer vollständig gelesen); falls die Datei kleiner als
der vorhandene Puffer ist wird der restliche Puffer gelöscht. Es
können nur durch den Befehl W{RITE}B geschriebene Dateien gelesen
werden. Die Voreinstellung für 'dateiname' ist 'MDHISDRV.BUF'.
Der Befehl RB überprüft nicht die Größe der zu lesenden Datei.
Die Befehle RB und WB können nur ausgeführt werden, falls DOS
nicht aktiv ist. (Da sie den DOS-Interrupt 21h zum Schreiben und
Lesen der Dateien benutzen.) Sie zeigen das Ergebnis als Fehler-
Meldung an (d.h. sie enden immer mit einem Fehler).
Die Befehle zum Lesen bzw. Schreiben des Puffers fangen auch
Hardware-Fehler ab.
Sie benutzen das PSP des gerade aktiven Prozesses.
H{ISTORY}=
Der Befehl H= zeigt den Status der History-Funktion (ein oder
aus) als Fehlermeldung an.
H{ISTORY}-
Der Befehl H- schaltet die History-Funktion aus. Im Unterschied
zur Taste <CTRL-V> zeigt dieser Befehl aber auch eine Meldung
(als Fehlermeldung) an.
H{ISTORY}+
Der Befehl H+ schaltet die History-Funktion ein. Im Unterschied
zur Taste <CTRL-R> zeigt dieser Befehl aber auch eine Meldung
(als Fehlermeldung) an.
BS
Dieser Befehl liefert im Register CX die Größe des eingerichteten
Puffers für die History-Funktion und im Register AX die Anzahl
der belegten Bytes im Puffer für die History-Funktion.
────────────────────────────────────────────────────────────────────────────────
Seite 10
En
Editieren des Inhaltes des Einzelpuffers mit der Nummer n. n muß
eine Ziffer zwischen 0 und 9 sein.
Der Treiber schreibt den Inhalt des Einzelpuffers hinter 'n: ' in
den Eingabepuffer von MDEBUG wo er dann editiert werden kann.
Beispiel:
E1
@ Editieren des Inhaltes des Einzelpuffers 1
Über den En-Befehl lässt sich somit auch feststellen, ob ein
Einzelpuffer schon belegt ist. Der Befehl löscht vor der Aus-
führung die Eingabe-Zeile von MDEBUG.
n: {befehlszeile}
Übernahme der Parameter des Befehls in den Einzelpuffer mit der
Nummer n. n muß eine Ziffer zwischen 0 und 9 sein. Die über-
nommene Befehlszeile wird nicht weiter bearbeitet.
Beispiel:
4: MOV AL,4
@ Übernahme des Befehls 'MOV AL,4' in den
@ Einzelpuffer mit der Nummer 4
Ln
Löschen des Einzelpuffers mit der Nummer n. n mß eine Ziffer
zwischen 0 und 9 sein.
Beispiel:
L9
@ Löschen des Einzelpuffers mit der Nummer 9
LA
Löschen aller Einzelpuffer
────────────────────────────────────────────────────────────────────────────────
Seite 11
MA
Sofortiges Ausführen des Einzelpuffers, dessen Nummer im Register
AL steht. Ein Wert größer als 9 im Register AL führt zu einem
Syntaxfehler.
Mn
Sofortiges Ausführen des Einzelpuffers n. n muß eine Ziffer
zwischen 0 und 9 sein.
Bei den Befehlen 'n:' und 'En' muß folgendes beachtet werden:
Falls mehrere verkettete Befehle in einen Einzelpuffer übernommen
werden sollen, müssen diese durch das Zeichen ~ getrennt werden.
Die Zeichen ~ und ^ können nicht in einer Befehlszeile für einen
Einzelpuffer gespeichert werden.
Beispiele:
3: MOV AL,4 ~ MOV BL,6 ~ MOV CL,7
@ Speichern der 3 Befehle im Einzelpuffer mit der Nummer 3
4: MOV AL,4 MOV BL,6 MOV CL,7
@ Speichern des Befehls
@ 'MOV AL,4'
@ und d. Kommentars (!)
@ 'MOV BL,6 MOV CL,7'
@ im Einzelpuffer mit der Nummer 4
5: MOV AL,5 ^ MOV BL,6 ^ MOV CL,7
@ Speichern des Befehls
@ 'MOV AL,5'
@ im Einzelpuffer mit der Nummer 5 und
@ sofortiges Ausführen (!) der Befehle
@ 'MOV BL,6' und 'MOV CL,7'.
────────────────────────────────────────────────────────────────────────────────
Seite 12
Einrichten von Macro-Befehlen
─────────────────────────────
Da der WB-Befehl die Inhalte der Einzelpuffer mitsichert, lassen
sich damit auch 10 zusätzliche Tastenbelegungen, die beim Start
automatisch geladen werden, realisieren.
Beispiel:
Zuerst werden die 10 Einzelpuffer mit den gewünschten Befehls-
zeilen belegt. Danach werden die Puffer über den WB-Befehl in
eine Datei gesichert. z.B.
WB MDAUTO.BEF
Nun müssen folgende Befehle in die Datei AUTOEXEC.BAT eingefügt
werden (die Kommentarzeilen natürlich nicht unbedingt):
REM Zuerst MDEBUG laden ...
MDEBUG
REM ... jetzt den Treiber laden (geht auch umgekehrt) ...
MDHISDRV
REM und nun über das Util CALLMDB den Treiber zum Laden
REM der Puffer aus der Datei veranlassen
CALLMDB "RB MDAUTO.BEF ^M" #0 "^M"
REM Der Code #0 (Simuliere leeren Tastaturpuffer) ist nötig,
REM da der Befehl RB mit einem Fehler endet und MDEBUG daher
REM den Tastaturpuffer leert so daß die restlichen Parameter
REM von CALLMDB ignoriert würden.
REM Das Passwort sollte ausgeschaltet sein, es kann aber
REM durch den Code der Taste <F3> (#3D00) hinter oder vor
REM den Parametern über CALLMDB eingeschaltet werden.
────────────────────────────────────────────────────────────────────────────────
Seite 13
MDDISDRV.COM
────────────
MDDISDRV.COM ist ein Kommandotreiber für MDEBUG. MDDISDRV.COM
stellt einen interaktiven Disassembler für MDEBUG zur Verfügung.
Der Disassembler kennt die Opcodes aller Prozessoren der 80x86-
Familie von INTEL bis einschließlich des 80386 und die Opcodes
der zugehörigen Coprozessoren 8087, 80287 und 80387. Ebenfalls
implementiert sind die Befehle, die nur auf dem weit verbreiteten
Prozessor V20 (bzw. V30) von NEC möglich sind (ausgenommen die
Befehle für den 8080-Emulation-Mode).
Nicht bzw. nur teilweise implementiert sind nur die beim 80386
vorhandenen Adress- und Operand-Size-Prefixe und die neuen Adres-
sierungsarten des 80386, da Programme unter DOS normalerweise nur
den 16-Bit-Modus des 80386 nutzen.
Installieren des Disassemblers
Der Disassembler kann folgendermaßen installiert werden:
MDDISDRV {/D{n}{,m}} {/Lnn} {/Fn{,}mm} {/Assss:oooo}
{/Sswitches} {/Pnn} {/Qn} {/I} {/R} {/H{1|0}}
{*{!}name} {&name} {?} {#} {@}
Parameter für MDDISDRV
(siehe auch 'Allgemeine Parameter für die Treiber')
/Dn,m - Drucker ändern
Mit dem Parameter '/Dn,m' kann der zu benutzende Drucker und die
maximale Anzahl Zeilen pro Seite für Datei- und Druckausgaben
festgelegt werden.
'n' ist die Nummer des zu verwendeten Druckers.
'n' muß eine Ziffer im Intervall zwischen 1 und 9 sein (1 = LPT1,
..., 9 = LPT9).
'm' ist die Anzahl der Zeilen pro Seite. 'm' kann jeder Wert im
Intervall zwischen 10 und 255 sein. Die maximale Anzahl Zeilen
pro Seite gilt für Datei- und Druckausgaben.
Soll nur die Anzahl der Zeilen pro Seite geändert werden, so kann
der Parameter auch in der Form '/D,m' angegeben werden.
Voreinstellung für 'n' ist 1 und für 'm' 55.
────────────────────────────────────────────────────────────────────────────────
Seite 14
/Lnn - Startzeile ändern
Mit dem Parameter '/Lnn' kann die Nummer der Bildschirmzeile für
die erste Zeile des Disassembler-Windows festgelegt werden.
'nn' ist die (dezimale) Nummer der Bildschirmzeile und muß ein
Wert im Intervall zwischen 1 und 7 sein.
Voreinstellung für 'nn' ist 2.
/Fn{,}mm - Farben ändern
Der Parameter '/Fn,mm' dient zur Änderung der vom Disassembler
verwendeten Farben für die Bildschirmausgabe.
'n' ist die Nummer der zu ändernden Farbe. Da der Disassembler
nur 3 Farben für die Ausgabe verwendet, muß 'n' eine Ziffer im
Intervall zwischen 1 und 3 sein.
'mm' ist die hexadezimale Angabe des Farbattributs für die
angegebene Farbnummer.
Das Farbattribut 'mm' ist dabei
folgendermaßen aufgebaut:
┌────────┬────────────────────────────┐
│ Bit(s) │ Bedeutung │
╞════════╪════════════════════════════╡
│ 0..3 │ Codierung der Vordergrund- │
│ │ Farbe Intervall: 0..0Fh │
│ 4..6 │ Codierung der Hintergrund- │
│ │ Farbe Intervall: 0..07h │
│ 7 │ Blinken ein (1) / aus (0) │
└────────┴────────────────────────────┘
Voreingestellt sind folgende
Farbattribute:
┌───────┬───────┬───────────────────┐
│ │ │ Wirkung auf │
│ Farbe │ Attr. │ s/w-Monitoren │
╞═══════╪═══════╪═══════════════════╡
│ 1 │ 07h │ grau auf schwarz │
│ 2 │ 0Fh │ weiß auf schwarz │
│ 3 │ 70h │ schwarz auf weiß │
└───────┴───────┴───────────────────┘
Die Farbnummer und das Farbattribut können durch ein Komma
getrennt werden.
────────────────────────────────────────────────────────────────────────────────
Seite 15
/Assss:oooo - Start-Adresse ändern
Mit diesem Parameter kann die Start-Adresse des Disassemblers
festgelegt werden.
'ssss' und 'oooo' müssen hexadezimale Werte zwischen 0000h und
0FFFFh sein.
Voreinstellung für 'ssss:oooo' ist F000h:FFF0h, also die Start-
Adresse des Prozessors nach einem Reset.
/Sswitches - Schalter ändern
Über den Parameter '/Sswitches' können die Voreinstellungen für
verschiedene Schalter des Disassemblers geändert werden.
'switches' muß eine beliebige Kombination der folgenden Schalter
sein:
(die mit (*) markierten Werte sind jeweils die Voreinstellung)
┌────────┬────────────────────────────────────────────────────────┐
│ Switch │ Bedeutung │
╞════════╪════════════════════════════════════════════════════════╡
│ a (*)│ bestehende Dateien überschreiben │
├────────┼────────────────────────────────────────────────────────┤
│ A │ bestehende Dateien verlängern │
├────────┼────────────────────────────────────────────────────────┤
│ F │ Datei- und Druckausgaben formatieren │
├────────┼────────────────────────────────────────────────────────┤
│ f (*)│ Datei- und Druckausgaben nicht formatieren │
├────────┼────────────────────────────────────────────────────────┤
│ B (*)│ Stackblocking ausschalten │
├────────┼────────────────────────────────────────────────────────┤
│ b │ Stackblocking einschalten │
├────────┼────────────────────────────────────────────────────────┤
│ U │ Ausgabe von unbekannten Opcodes mit einem Byte │
├────────┼────────────────────────────────────────────────────────┤
│ u (*)│ Ausgabe von unbekannten Opcodes mit zwei Bytes │
├────────┼────────────────────────────────────────────────────────┤
│ P (*)│ Ausgabe von Prefixen vor den Befehlen │
├────────┼────────────────────────────────────────────────────────┤
│ p │ Ausgabe von Prefixen als einzelne Befehle │
└────────┴────────────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 16
┌────────┬────────────────────────────────────────────────────────┐
│ Switch │ Bedeutung │
╞════════╪════════════════════════════════════════════════════════╡
│ W (*)│ Ausgabe von WAIT-Befehlen ab dem 80827 als einzelne │
│ │ Befehle │
├────────┼────────────────────────────────────────────────────────┤
│ w │ WAIT-Befehle immer als Teil des Befehls ausgeben │
├────────┼────────────────────────────────────────────────────────┤
│ R (*)│ Anzeige im Dump-Modus kontinuierlich updaten │
├────────┼────────────────────────────────────────────────────────┤
│ r │ Anzeige im Dump-Modus nur nach einem Tastendruck │
│ │ updaten │
├────────┼────────────────────────────────────────────────────────┤
│ K (*)│ Kommentare ausgeben │
├────────┼────────────────────────────────────────────────────────┤
│ k │ Kommentare nicht ausgeben │
├────────┼────────────────────────────────────────────────────────┤
│ Axx │ Modus für die Ausgabe von Offsets und Displacements │
│ │ festlegen, Bedeutung von 'xx': │
│ │ ┌─────┬─────────┬──────────┐ │
│ │ │ xx │ Code │ Daten │ │
│ │ ╞═════╪═════════╪══════════╡ │
│ (*)│ │ aa │ absolut │ absolut │ │
│ │ │ ra │ relativ │ absolut │ │
│ │ │ ar │ absolut │ relativ │ │
│ │ │ rr │ relativ │ relativ │ │
│ │ └─────┴─────────┴──────────┘ │
├────────┼────────────────────────────────────────────────────────┤
│ Dx │ Anzeige-Modus festlegen, Bedeutung von 'x': │
│ │ ┌───┬──────────────────────┐ │
│ │ │ x │ Modus │ │
│ │ ╞═══╪══════════════════════╡ │
│ (*)│ │ a │ Disassembler-Modus │ │
│ │ │ A │ Assembler-Modus │ │
│ │ │ D │ Dump-Modus │ │
│ │ └───┴──────────────────────┘ │
├────────┼────────────────────────────────────────────────────────┤
│ Lx │ Modus für die Ermittlung der vorherigen Instruktion │
│ │ festlegen, Bedeutung von 'x': │
│ │ ┌───┬─────────────────────────────────────────────────┐│
│ │ │ x │ Modus ││
│ │ ╞═══╪═════════════════════════════════════════════════╡│
│ │ │ s │ ermittle den kürzesten Befehl ││
│ │ │ l │ ermittle den längsten Befehl ││
│ (*)│ │ p │ ermittle die vorherige Instruktion seitenweise ││
│ │ └───┴─────────────────────────────────────────────────┘│
└────────┴────────────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 17
Die Schalter können in beliebiger Reihenfolge angegeben und durch
Kommas getrennt werden. Mehrdeutige Schalter (z.B. 'A' und 'Ara')
müssen durch Komma getrennt werden. Bei mehrmaliger Angabe eines
Schalters oder bei Angabe mehrerer sich ausschließender Schalter
wird der letzte angegebene Schalter benutzt. Die Schalter werden
nur bei der Installation berücksichtigt, sie können aber auch im
interaktivem Modus des Disassemblers noch beliebig geändert
werden. (siehe 'Die Schalter des Disassemblers')
Bei den Schaltern wird zwischen Groß- und Kleinschreibung unter-
schieden!
/H{1|0} - Benutzung der UMBs einstellen
Mit diesem Parameter kann festgelegt werden, ob der residente
Teil von MDDISDRV in einen Speicherbereich oberhalb von A000h
verschoben werden soll (n = 1) oder nicht (n = 0). Voreinstellung
für n ist 0. Falls der Parameter in der Form '/H' angegeben wird,
wird der aktuelle Wert von n umgeschaltet. Falls der Parameter
'/H1' angegeben wird, und kein freier Speicherbereich in der
benötigten Größe oberhalb von A000h vorhanden ist (z.B. bei DOS-
Versionen vor 5.00 ohne speziellen Speichermanager oder falls
alle Blöcke oberhalb von A000h schon belegt sind), wird der
residente Teil von MDDISDRV im Speicherbereich unterhalb von
A000h belassen.
Der Parameter wird nur bei der Installation des Treibers berück-
sichtigt.
*{!}name - Sichern des Status des Disassemblers
Über diesen Parameter kann der Status des Disassemblers in eine
Datei gesichert werden. 'name' ist hierbei der Name der Datei
(evtl. inclusive Pfad). Falls vor dem Dateinamen ein führendes
Rufzeichen ('!') angegeben wird, wird eine bestehende Datei
überschrieben. Ansonsten führt eine bestehende Datei zu einem
Fehler.
Falls schon eine residente Version des Disassemblers geladen ist,
wird deren Status gesichert. Der Parameter '*name' wird in diesem
Fall vor dem zusätzlich möglichen Parameter '/R' ausgeführt.
Gesichert werden die folgenden Daten:
- die aktuellen Werte der Schalter, Variablen und Modi des
Disassemblers
- die Start-Adresse
- die Adressen aller Marker
- der komplette Adressen-Stack
- die Daten der letzten Referenz-Suche
- die Inhalte der Segment-Register und des Registers HB
- die Start-Zeile und die Farben des Windows
- die aktuelle Seite der Online-Hilfe
- die aktuellen Werte für die Taste <0>
────────────────────────────────────────────────────────────────────────────────
Seite 18
&name - Laden des Status des Disassemblers
Mit dem Parameter '&name' kann der Status des Disassemblers aus
einer (durch den Parameter '*name' erstellten) Datei gelesen
werden. Falls schon eine residente Version des Disassemblers
geladen ist, wird deren Status verändert.
Falls die Parameter '&name' und '*name' zusammen angegeben
werden, wird immer zuerst der Parameter '*name' ausgeführt. Der
Parameter wird ebenfalls vor dem evtl. zusätzlich angegebenen
Parameter '/R' ausgeführt.
Hinweis:
Der Parameter '&name' wird nach den anderen Parametern ausge-
führt, so daß er bei der Erstinstallation die Angaben bzw. Vor-
einstellungen für die Parameter '/D', '/L', '/F', '/A', '/S'
und '/Q' überschreibt.
/Qn - Quiet-Modus ein/ausschalten
Ein- (n=1) oder Ausschalten (n=0 Voreinstellung) des Quiet-Modus.
Im Quiet-Modus werden alle akustischen Ausgaben des Disassemblers
unterdrückt.
# - Ausgabe der Codes der Funktionstasten
Ausgabe der internen Tabelle mit den Codes für die Funktions-
tasten zum Aufruf der einzelnen Funktionen des Disassemblers.
(siehe die Beschreibung des Parameters '#' und die Beschreibung
der Installation in der Dokumentation von MDEBUG)
────────────────────────────────────────────────────────────────────────────────
Seite 19
Aufruf des Disassemblers in MDEBUG
──────────────────────────────────
Nachdem der Treiber MDDISDRV installiert wurde (vor oder nach
MDEBUG), kann der Disassembler in MDEBUG über folgende Tasten
bzw. Befehle aufgerufen werden:
Aufruf des Disassemblers im Monitor von MDEBUG
──────────────────────────────────────────────
<F5> - Aufruf des Disassemblers mit den aktuellen Werten
des Disassemblers
<SHIFT-F5> - Aufruf des Disassemblers mit dem Doppelwort auf dem
der Cursor steht
<CTRL-F5> - Aufruf des Disassemblers mit der Adresse des Bytes
auf dem der Cursor steht.
<ALT-F5> - Aufruf des Disassemblers mit dem Monitor-Segment als
Segment und dem Wort auf dem der Cursor steht als
Offset für die Start-Adresse
Aufruf des Disassemblers im Interpreter von MDEBUG
──────────────────────────────────────────────────
<F5> - Aufruf des Disassemblers mit den aktuellen Werten
des Disassemblers
<SHIFT-F5> - Aufruf des Disassemblers mit der Return-Adresse
(RS:RO) als Start-Adresse. Zusätzlich werden die
Segment-Register DS, ES und SS des Disassemblers mit
den Werten der Segment-Register von MDEBUG geladen.
<CTRL-F5> - Aufruf des Disassemblers mit der Monitor-Start-
Adresse als Start-Adresse
Hinweis: Falls der Disassember über eine der o.a. Tasten (außer
<F5>) aufgerufen wird, startet er immer im Disassembler-
bzw. Assembler-Modus.
────────────────────────────────────────────────────────────────────────────────
Seite 20
Aufruf des Disassemblers durch Befehle in MDEBUG
────────────────────────────────────────────────
DI {{ssss:}oooo}
Aufruf des Disassemblers mit 'ssss' als Segment und 'oooo' als
Offset für die Start-Adresse. 'ssss' und 'oooo' müssen hexadezi-
male Werte zwischen 0h bis 0FFFFh sein. Ausdrücke, Register oder
Konstanten können nicht benutzt werden. Voreingestellt für 'ssss'
und 'oooo' sind die aktuellen Werte des Disassemblers.
DI In
Aufruf des Disassemblers mit der Adresse des Interrupts 'n' als
Start-Adresse. 'n' muß ein hexadezimaler Wert im Intervall von
0 bis 0FFh sein. Ausdrücke, Register oder Konstanten sind nicht
möglich.
Weitere Befehle des Disassemblers für MDEBUG
────────────────────────────────────────────
DC {text}
Ausgabe des Textes 'text' auf den akt. Drucker des Disassemblers.
Hinweis:
Falls hinter dem DC-Befehl kein weiterer Befehl folgt, werden
alle folgenden Leerzeichen bis zum Ende der Eingabezeile von
MDEBUG mit ausgegeben. Soll dies unterbunden werden, muß das
Ende der Parameter des Befehls durch das Verkettungszeichen von
MDEBUG ('^') gekennzeichnet werden.
Der Befehl kann nur genutzt werden, falls DOS nicht aktiv ist.
Hinweis: Hier gelten die gleichen Einschränkungen wie bei der
Ausgabe von Speicherbereichen auf den Drucker.
(siehe 'Allgemeines zum Sichern von Speicherbereichen')
SM
Übernahme der Start-Adresse des Disassemblers in die Register SE
und OF von MDEBUG.
────────────────────────────────────────────────────────────────────────────────
Seite 21
Bedienung des Disassemblers
───────────────────────────
Aufbau der Windows
──────────────────
────────────────────────────────────────────────────────────────────────────────
╔══ MDDISDRV V2.05 ══════ Ziel-CPU: V20/----- ══[inst. CPU: V20/-----]═════╗
║ 2D69:423A B8 FD FF MOV AX,0FFFD ;=65533 [ 8086]+ ║
║ 2D69:423D E9 96 FE JMP 040D6 [ 8086]+ ║
║ 2D69:4240 3C 41 CMP AL,041 ; 'A' = 65 = 0100_0001xB [ 8086]+ ║
->║ 2D69:4242 72 0E JB 04252 [ 8086]+ ║
║ 2D69:4244 3C 5A CMP AL,05A ; 'Z' = 90 = 0101_1010xB [ 8086]+ ║
║ 2D69:4246 77 0A JA 04252 [ 8086]+ ║
║ 2D69:4248 2C 41 SUB AL,041 ; 'A' = 65 = 0100_0001xB [ 8086]+ ║
║ 2D69:424A 53 PUSH BX [ 8086]+ ║
║ 2D69:424B BB 4F 12 MOV BX,0124F ;= 4687 [ 8086]+ ║
║ 2D69:424E D7 XLAT [ 8086]+ ║
╟─ akt. Stack-Element: 5 ── Disp. Code: A Daten: A ─[BPuWRfapK]──[lpt1, 55]───╢
║ 2D69:411F 2D69:410A 2D69:40DD 2D69:40CA 2D69:40AD ║
╟─ Register: CS: 2D69 DS: 2D69 ES: 022C SS: 022C GS: 0000 FS: 0000 HB: 0000 ──╢
╠ 2D69:4252 F9 STC [ 8086]+ ╣
║ 2D69:4253 C3 RET [ 8086]+ ║
║ < Tastenbelegung > ║
╚══════════════════════[ (c) 1991 - 1992 Bernd Schemmer ]══════════════════════╝
────────────────────────────────────────────────────────────────────────────────
Abb. 1 - Aufbau des Windows im Disassembler-Modus
Aufbau des Windows im Disassembler-Modus
────────────────────────────────────────
[siehe Abb. 1]
Im Disassembler-Modus zeigt der Disassembler auf dem oberen
Rahmen des Windows die Ziel-CPUs und die installierten CPUs an.
Die Ziel-CPUs sind die Prozessoren (Prozessor und Coprozessor)
für die disassembliert wird. D.h. der Disassembler erkennt immer
nur die Opcodes, die auch die aktuellen Ziel-CPUs erkennen. Die
Ziel-CPUs werden mit den real installierten Prozessoren initiali-
siert, können aber jederzeit geändert werden. Hierbei sind alle
Variationen von Ziel-CPU und Ziel-CoCPU möglich.
────────────────────────────────────────────────────────────────────────────────
Seite 22
Die Ziel-CPUs sind völlig unahängig von den real vorhandenen
Prozessoren. Zwischen den CPU-Versionen mit 16-Bit-Bus und 8-Bit-
Bus (z.B. 8086 und 8088) wird nicht unterschieden. Gleiches
gilt für die CPU-Versionen mit 32-Bit- oder 16-Bit-Bus (z.B. der
80386SX und der 80386)
Die installierten CPUs sind die real vorhandenen Prozessoren. Sie
werden nur einmal im Initialisierungsteil des Programms ermittelt
und können nicht geändert werden.
Die Angabe dient nur informatorischen Zwecken.
Falls kein Coprozessor installiert ist oder keine Ziel-CoCPU
gewählt wurde, so wird als Name des Coprozessors bzw. der Ziel-
CoCPU '-----' ausgegeben.
In den folgenden 10 Zeilen wird jeweils ein disassemblierter
Befehl angezeigt. [siehe Abb. 2]
────────────────────────────────────────────────────────────────────────────────
┌1. Feld┐ ┌───── 2. Feld ────┐ ┌───────── 3. Feld ───────────────┐ ┌4. Feld┐
│ │ │ │ │ │ │ │
║ 35B9:0216 BB 3A 03 MOV BX,033A ;= 826 [ 8086]+ ║
┌──────── ┌──────────────────── ┌────────────────────────────────── ┌───────
│ │ │ │
│ │ │ └─ min.
│ │ └─ Prefixe, Mnemonic, Operanden benötigte
│ │ und Kommentare CPU für
│ │ den Befehl
│ └─ Byte(s) des Opcode in hexadezimaler Form
│
└─ Adresse des akt. Befehls (segment:offset, hexadezimal)
────────────────────────────────────────────────────────────────────────────────
Abb. 2 - Aufbau einer Zeile im Disassembler-Modus
────────────────────────────────────────────────────────────────────────────────
Seite 23
Hinter dem Namen des mindestens für den Befehl nötigen Prozessors
folgt noch ein bzw. zwei weitere Zeichen für die nähere Spezifi-
zierung des nötigen Prozessors. Hierbei gilt:
Ein '+' bedeutet, daß der Befehl ab dem angegebenen Prozessor
möglich ist, das Zeichen '*' wird ausgegeben, falls der Befehl
NUR auf dem angegebenen Prozessor möglich ist und ein 'P' zeigt
an, daß der Befehl ab dem angegebenen Prozessor aber nur im
Protected Mode möglich ist.
Befehle, die auf mehreren, aber nicht auf allen Prozessoren
möglich sind z.B. 'MOV AX,CS' (siehe 'OPCODES.PRT'), werden durch
die beiden Zeichen '+*' gekennzeichnet. Ebenfalls mit diesen
beiden Zeichen markiert werden die Befehle, die von den Prozes-
soren unterschiedlich ausgeführt werden (z.B. 'PUSH SP' oder
'AAD' falls das zweite Byte des Opcode nicht 0Ah ist).
Die nächste Zeile ist die Statuszeile des Disassemblers. Hier
werden die Anzahl der Elemente auf dem Adressen-Stack, die aktu-
ellen Modi für die Ausgabe von Offsets und Displacements (oder
der aktuelle Modus für die Dumpzeile) und die aktuellen Werte der
Schalter angezeigt. [siehe Abb. 3a und 3b]
────────────────────────────────────────────────────────────────────────────────
Anzahl Zeilen/Seite ──┐
akt. Drucker ─┐ │
└──── └──
╟─ akt. Stack-Element: 1 ── Disp. Code: A Daten: A ───[BPuWRfapK]─[lpt1, 55]───╢
│ │ │ │││││││││
Anzahl der Elemente │ │ │ │││││││││
auf dem Stack ───────┘ │ │ │││││││││
│ │ │││││││││
Anzeige-Modus für JMP/CALL-Displacements ┘ │ │││││││││
│ │││││││││
Anzeige-Modus für Daten-Offsets ───────────────┘ │││││││││
│││││││││
Schalter B (mögliche Werte: 'B' und 'b') ──┘││││││││
Schalter P (mögliche Werte: 'P' und 'p') ────┘│││││││
Schalter U (mögliche Werte: 'U' und 'u') ──────┘││││││
Schalter W (mögliche Werte: 'W' und 'w') ────────┘│││││
Schalter R (mögliche Werte: 'R' und 'r') ──────────┘││││
Schalter F (mögliche Werte: 'F' und 'f') ────────────┘│││
Schalter A (mögliche Werte: 'A' und 'a') ──────────────┘││
Schalter L (mögliche Werte: 's', 'l', und 'p') ──────────┘│
Schalter K (mögliche Werte: 'K' und 'k') ──────────────────┘
────────────────────────────────────────────────────────────────────────────────
Abb. 3a - Aufbau der Statuszeile des Disassemblers im (Dis)Assembler-Modus
────────────────────────────────────────────────────────────────────────────────
Seite 24
────────────────────────────────────────────────────────────────────────────────
Anzahl Zeilen/Seite ──┐
akt. Drucker ─┐ │
└──── └──
╟─ akt. Stack-Element: 2 ── DumpLineModus: AW ──────[BPuWRfapk]──[lpt1, 55]───╢
│ ┌─ │││││││││
Anzahl der Elemente │ │ │││││││││
auf dem Stack ───────┘ │ │││││││││
│ │││││││││
Anzeige-Modus für die Dump-Zeile ────────┘ │││││││││
1. Zeichen: A - (Dis)Assembler-Modus │││││││││
D - Dump-Modus │││││││││
2. Zeichen: W - Segment = Register DS │││││││││
D - Segment = 2. Wort aus der akt. │││││││││
Zeile │││││││││
Der Offset wird in allen 4 Fällen aus dem 1. Wort │││││││││
der aktuellen Zeile ermittelt. │││││││││
│││││││││
Schalter B (mögliche Werte: 'B' und 'b') ──┘││││││││
Schalter P (mögliche Werte: 'P' und 'p') ────┘│││││││
Schalter U (mögliche Werte: 'U' und 'u') ──────┘││││││
Schalter W (mögliche Werte: 'W' und 'w') ────────┘│││││
Schalter R (mögliche Werte: 'R' und 'r') ──────────┘││││
Schalter F (mögliche Werte: 'F' und 'f') ────────────┘│││
Schalter A (mögliche Werte: 'A' und 'a') ──────────────┘││
Schalter L (mögliche Werte: 's', 'l', und 'p') ──────────┘│
Schalter K (mögliche Werte: 'K' und 'k') ──────────────────┘
────────────────────────────────────────────────────────────────────────────────
Abb. 3b - Aufbau der Statuszeile des Disassemblers im Dump-Modus
Die folgende Zeile dient zur Anzeige der obersten 7 Elemente auf
dem Adressen-Stack. Das oberste Element des Adressen-Stacks (also
die Adresse, die beim nächstem pop vom Adressen-Stack entfernt
wird, s.u.) wird in der Farbe 2 angezeigt.
Adressen, die im Dump-Modus auf den Adressen-Stack gepusht worden
sind, werden zusätzlich durch das Zeichen '*' vor der Adresse
gekennzeichnet.
Auf dem linken Rand, vor der ersten Adresse, wird ein 'V' ausge-
geben, falls der Adressen-Stack voll ist. Hinter der letzten
angezeigten Adresse wird das Zeichen '»' ausgegeben, falls auf
dem Adressen-Stack mehr als 7 Adressen sind.
────────────────────────────────────────────────────────────────────────────────
Seite 25
In der nächsten Zeile werden die Inhalte der Segment-Register
CS, DS, ES, SS, FS und GS und der Inhalt des Hilfsregisters HB
des Disassemblers ausgegeben. Die hier angezeigten Werte werden
vom Disassembler zur Ermittlung des Segments (und das Hilfs-
register HB für die Ermittlung des Offsets, s.u.) der Adresse aus
einem Befehl benutzt. Der Inhalt der der aktuellen CPU bekannten
Segment-Register wird in der Farbe 2 ausgegeben.
Der Inhalt der nächsten beiden Zeilen ist abhängig vom Befehl in
der aktuellen Zeile:
Falls der aktuelle Befehl einen expliziten Speicheroperanden
enthält, werden in der nächsten Zeile ein Ruler und in der über-
nächsten Zeile die ersten 16 Byte des Speicheroperanden in hexa-
dezimaler Form und als ASCII-Codes angezeigt.
Enthält der aktuelle Befehl eine implizite oder explizite Sprung-
Adresse, so werden in den beiden folgenden Zeilen die beiden
ersten Befehle ab dieser Adresse angezeigt.
In allen anderen Fällen wird nur der Ruler ausgegeben und die
vorletzte ist Zeile leer.
Das Segment der Adressen aus den Befehlen wird vom Disassembler
analog zur Vorgehensweise des Prozessors ermittelt. Ein Segment-
Prefix in der aktuellen Zeile wird nur berücksichtigt, falls es
auch vom Prozessor berücksichtigt würde.
Falls der Schalter R auf 'R' steht, wird der Inhalt der vor-
letzten Zeile(n) in allen Modi kontinuierlich upgedatet.
Die letzte Zeile des Windows dient zur Ausgabe der aktuellen
Tastenbelegung, der Meldungen und der Eingabe-Aufforderung bei
der Eingabe von Werten.
Die aktuelle Zeile des Disassemblers wird immer in der Farbe 3
ausgegeben.
Hinweis: In den Abbildungen ist die aktuelle Zeile jeweils durch
das Prefix '->' gekennzeichnet.
────────────────────────────────────────────────────────────────────────────────
Seite 26
────────────────────────────────────────────────────────────────────────────────
╔══ MDDISDRV V2.05 ══════ Ziel-CPU: V20/----- ══[inst. CPU: V20/-----]═════╗
->║ MOV AX,0FFFD ;=65533 ; 2D69:423A B8 FD FF [ 8086]+ ║
║ JMP 040D6 ; 2D69:423D E9 96 FE [ 8086]+ ║
║ CMP AL,041 ; 'A' = 65 ; 2D69:4240 3C 41 [ 8086]+ ║
║ JB 04252 ; 2D69:4242 72 0E [ 8086]+ ║
║ CMP AL,05A ; 'Z' = 90 ; 2D69:4244 3C 5A [ 8086]+ ║
║ JA 04252 ; 2D69:4246 77 0A [ 8086]+ ║
║ SUB AL,041 ; 'A' = 65 ; 2D69:4248 2C 41 [ 8086]+ ║
║ PUSH BX ; 2D69:424A 53 [ 8086]+ ║
║ MOV BX,0124F ;= 4687 ; 2D69:424B BB 4F 12 [ 8086]+ ║
║ XLAT ; 2D69:424E D7 [ 8086]+ ║
╟─ akt. Stack-Element: 5 ── Disp. Code: A Daten: A ─[BPuWRfapK]──[lpt1, 55]───╢
║ 2D69:411F 2D69:410A 2D69:40DD 2D69:40CA 2D69:40AD ║
╟─ Register: CS: 2D69 DS: 0070 ES: 022C SS: 022C GS: 0000 FS: 0000 HB: 0000 ──╢
╠══seg:off══╤ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F ╤0123456789ABCDEF╣
║ 0070:FFFD │ 00 00 00 61 1B 2A 18 1B-1A C4 09 74 0A 71 06 80 │...a.*...─.t.q.Ç║
║ < Tastenbelegung > ║
╚══════════════════════[ (c) 1991 - 1992 Bernd Schemmer ]══════════════════════╝
────────────────────────────────────────────────────────────────────────────────
Abb. 4 - Aufbau des Windows im Assembler-Modus
Aufbau des Windows im Assembler-Modus
─────────────────────────────────────
[siehe Abb. 4]
Der Aufbau des Windows im Assembler-Modus ist äquivalent zum
Aufbau des Windows im Disassembler-Modus. Im Assembler-Modus ist
nur die Reihenfolge der einzelnen Felder verändert.
[siehe Abb. 4 und Abb. 5]
Dieser Modus ist vor allen zur Sicherung von disassemblierten
Code in eine Datei sinnvoll (s.u.).
────────────────────────────────────────────────────────────────────────────────
Seite 27
────────────────────────────────────────────────────────────────────────────────
┌───── 1. Feld ───────────────┐ ┌ 2. Feld ┐ ┌──── 3. Feld ──────┐ ┌4. Feld┐
│ │ │ │ │ │ │ │
║ MOV BX,013C ;= 826 35B9:0218 BB 3C 01 [ 8086]+ ║
┌────────────────────────────── ┌────────── ┌──────────────────── ┌───────
│ │ │ │
│ │ └─ Byte(s) des └─ min.
│ │ Opcodes benötigte
│ │ CPU für
│ │ den Befehl
│ └─ Adresse des Befehls (hex.)
└─ Prefixe, Mnemonic, Operanden
und Kommentare
────────────────────────────────────────────────────────────────────────────────
Abb. 5 - Aufbau einer Zeile im Assembler-Modus
Aufbau des Windows im Dump-Modus
────────────────────────────────
────────────────────────────────────────────────────────────────────────────────
╔══seg:off══╤ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F ╤0123456789ABCDEF╗
║ 022C:0E00 │ 98 63 79 22 82 22 3C 23-59 23 5F 23 C4 21 F0 21 │ÿcy"é"<Y_─ . ║
->║ 022C:0E10 │ 55 1F BB 1F C7 1F 73 23-7D 23 50 1C 4C 1B 88 2A │U.╗.╟.s}P.L.ê* ║
║ 022C:0E20 │ 25 24 87 2B 1B 2C C2 23-73 2B 78 2B 59 2B 97 24 │ $ç+.,┬s+x+Y+ù$ ║
║ 022C:0E30 │ 86 16 47 1B 3C 1B D9 1B-DB 1B 86 16 86 16 1F 1C │å.G.<.┘.█.å.å...║
║ 022C:0E40 │ 86 16 7D 2B 82 2B D6 23-AA 23 6E 1B 01 1D 6E 2B │å.}+é+╓¬n...n+ ║
║ 022C:0E50 │ 69 2B CE 1B 91 17 AE 17-CE 17 DF 17 8A 19 28 1B │i+╬.æ.«.╬.▀.è.(.║
║ 022C:0E60 │ 6C 19 3C 63 21 1C 12 14-07 1C 5E 1B FD 1A 86 1B │l.<c .....^.².å.║
║ 022C:0E70 │ 91 19 6D 2E B5 2D F1 2D-BE 6F FF 6E 99 6C AB 6D │æ.m.╡-±-╛o nÖl½m║
║ 022C:0E80 │ FF 6D 10 70 04 6E CB 6F-91 2E BB 6E DB 6E 4D 2D │ m.p.n╦oæ.╗n█nM-║
║ 022C:0E90 │ 1E 64 3B 65 17 65 FA 5E-74 63 F0 5E 8E 2C E6 2C │.d;e.e·^tc.^Ä,µ,║
╟─ akt. Stack-Element: 5 ── DumpLineModus: AW ──────[BPuWRfapK]──[lpt1, 55]───╢
║ *2D69:4000 2D69:410A 2D69:40DD 2D69:40CA 2D69:40AD ║
╟─ Register: CS: 022C DS: 022C ES: 022C SS: 022C GS: 0000 FS: 0000 HB: 0000 ──╢
╠ 022C:1F55 1E PUSH DS [ 8086]+ ╣
║ 022C:1F56 56 PUSH SI [ 8086]+ ║
║ < Tastenbelegung > ║
╚══════════════════════[ (c) 1991 - 1992 Bernd Schemmer ]══════════════════════╝
────────────────────────────────────────────────────────────────────────────────
Abb. 6 - Aufbau des Windows im Dump-Modus
────────────────────────────────────────────────────────────────────────────────
Seite 28
Im Dump-Modus werden auf dem oberen Rahmen des Windows ein Ruler
und in den folgenden 10 Zeilen jeweils 16 Byte des aktuellen
Speicherbereichs in hexadezimalen Format und als ASCII-Codes
angezeigt. [siehe Abb. 6]
────────────────────────────────────────────────────────────────────────────────
┌1. Feld┐ ┌────────────── 2. Feld ──────────────────────┐ ┌── 3. Feld ───┐
│ │ │ │ │ │
║ 35B9:023A │ FE FE EB 04 83 4E FE 01-B0 FF 89 46 FC 2E 8B 26 │■■δ.âN■.░ ëFⁿ.ï&║
┌──────── ┌────────────────────────────────────────────── ┌───────────────
│ │ │
│ │ └─ 16. Bytes des
│ │ Speicherbereichs
│ └── 16 Bytes des Speicherbereichs in als ASCII-Codes
│ hexadezimaler Form ASCII-Codes kleiner
│ als 32 werden als
│ '.' dargestellt.
│
└─ Adresse des Speicherbereichs (segment:offset, hexadezimal)
────────────────────────────────────────────────────────────────────────────────
Abb. 7 - Aufbau einer Zeile im Dump-Modus
Der Aufbau der restlichen Zeilen ist, bis auf die beiden vor-
letzten Zeilen, mit dem Aufbau der Zeilen im Disassembler-Modus
identisch.
Im Dump-Modus kann der Modus für die letzten beiden Zeilen frei
gewählt werden. Zur Verfügung stehen hierbei folgende Modi:
1. Anzeige der Daten ab der Adresse, die im ersten Doppelwort in
der aktuellen Zeile steht, im Dump-Modus. (DumpLineModus: DD)
2. Anzeige der Daten ab der Adresse mit dem Offset aus dem ersten
Wort in der aktuellen Zeile und dem Inhalt des Register DS als
Segment-Register im Dump-Modus. (DumpLineModus: DW)
3. Anzeige des dissassemblieren Codes ab der Adresse, die im
ersten Doppelwort in der aktuellen Zeile steht.
(DumpLineModus: AD)
4. Anzeige des disassemblieren Codes ab der Adresse mit dem
Offset aus dem ersten Wort in der aktuellen Zeile und dem
Inhalt des Registers DS als Segment. (DumpLineModus: AW)
────────────────────────────────────────────────────────────────────────────────
Seite 29
Tastenbelegung des Disassemblers
────────────────────────────────
Der Disassembler kann über verschiedene Tasten und Tastenkombi-
nation gesteuert werden. Diese werden im folgenden erläutert.
Bei den Beschreibungen werden folgende Vereinbarungen benutzt:
o 'Start-Adresse' bezeichnet immer die Adresse aus der ersten
Zeile des Windows des Disassemblers.
o Die aktuelle Zeile ist immer die Zeile, die in der Farbe 2 an-
gezeigt wird. In den Abbildungen ist diese Zeile durch das
Prefix '->' gekennzeichnet.
Die Tasten können, falls nichts anderes angegeben ist, in allen
Anzeige-Modi benutzt werden.
<F2> - Ändern der Ziel-CPU.
<SHIFT-F2> - Ändern der Ziel-CoCPU
<F3> - Wechseln zwischen dem Dump- und Disassembler-Modus
<CTRL-F3> - Ändern des Modus für die Dump-Zeile im Dump-Modus
(= DumpLineModus)
<CursorUp>, <CursorDown>
<Blank> - zeilenweises Scrollen des Speicherbereichs
<PgUp>, <PgDn>
<RETURN> - seitenweises Scrollen des Speicherbereichs
────────────────────────────────────────────────────────────────────────────────
Seite 30
<CTRL-CursorUp>, <+>
- Erhöhen des Offsets der Start-Adresse um 1
<CTRL-CursorDown>, <->
- Vermindern des Offsets der Start-Adresse um 1
<W> - Erhöhen des Offsets der Start-Adresse um 2
<A> - Vermindern des Offsets der Start-Adresse um 2
<0> - Nochmalige Anzeige des letzten Speicherbereichs
<CTRL-T> - Aktuelle Zeile zur ersten Zeile im Window machen
<Home> - Erste Zeile des Windows zur aktuellen Zeile machen
<End> - Letzte Zeile des Windows zur aktuellen Zeile machen
<F4>, <J> - Eingabe einer neuen Start-Adresse
Die Eingabe einer neuen Start-Adresse muß im hexadezimalen Format
erfolgen. Der Cursor wird bei der Eingabe durch ein blinkendes
Zeichen und/oder durch eine andere Farbe für das aktuelle Zeichen
dargestellt - dies ist abhängig vom Modus der installierten
Graphik-Karte und vom Farbattribut für die Farbe 2. Während der
Eingabe gilt immer der Overwrite-Modus.
Hinweis: Falls der Cursor nicht sichtbar ist, muß die Farbe 1 und
/oder die Farbe 2 geändert werden.
Zur Positionierung des Cursors bei der Eingabe können die Tasten
<CursorRight>, <CursorLeft>, <Home> und <End> verwendet werden.
Die Taste <Tab> positioniert den Cursor auf den Anfang des Feldes
für den Offset und die Taste <SHIFT-Tab> positioniert den Cursor
auf den Anfang des Feldes für das Segment.
Beendet wird die Eingabe mit <RETURN>. <ESC> bricht die Änderung
ab, d.h. die Start-Adresse wird nicht verändert. Beachtet werden
muß, daß, falls das Segment der Start-Adresse geändert wird,
auch implizit das Segment-Register CS neu besetzt wird (auch im
Dump-Modus).
────────────────────────────────────────────────────────────────────────────────
Seite 31
<I> - Anzeige des Codes für einen Interrupt
Nach der Eingabe von I kann die Nummer des Interrupts, dessen
Code disassembliert werden soll, im hexadezimalem Format ange-
geben werden (Intervall: 0..0FFh).
Bei der Eingabe gelten die gleichen Tasten wie bei der Eingabe
einer neuen Start-Adresse (mit Ausnahme der Tasten <SHIFT-Tab>
und <Tab>, die hier analog der Taste <Home> belegt sind.).
<F5> - Ändern der Inhalte der Register
Beim Editieren der Inhalte der Register gelten ebenfalls die
gleichen Tasten wie bei der Eingabe einer neuen Start-Adresse.
Ausgenommen hiervon sind nur die Tasten <Tab> und <SHIFT-Tab>
die hier zum Wechseln des Registers dienen.
Durch die Änderung des Registers CS wird auch das Segment der
Start-Adresse geändert!
Der Inhalt des Register CS wird zudem immer implizit geändert,
falls die Start-Adresse verändert wird.
<SHIFT-F5>
Lädt die Register DS, ES, SS und, falls als Ziel-CPU der 80386
gewählt wurde, FS und GS mit dem Wert aus dem Register CS.
<C>, <D>, <E>, <S>, <F>, <G>
Editieren des Inhaltes des Segment-Registers mit dem eingegebenen
Buchstaben als Anfangsbuchstaben. (z.B. <E> ->> Register ES)
<H> - Editieren des Inhaltes des Hilfsregisters
<CTRL-N> - Normalisieren der Start-Adresse so das gilt
0 <= Offset <= 0Fh
(ohne Berücksichtigung eines evtl. Überlaufs)
<ESC>, <Q>
- Disassembler verlassen, Rückkehr nach MDEBUG
<F10>, <X>
- Disassembler und MDEBUG verlassen
────────────────────────────────────────────────────────────────────────────────
Seite 32
<CTRL-F10>
Übernahme der Start-Adresse des Disassemblers in die Register SE
und OF des Monitors von MDEBUG und Verlassen des Disassemblers.
<ALT-F10>
Falls auf die aktuelle Zeile die Funktion 'Folge dem Befehl'
möglich ist (s.u.), wird die Adresse aus der aktuellen Zeile in
die Register SE und OF des Monitors von MDEBUG übernommen und der
Disassembler verlassen.
<ALT-F5>
Disassembler und MDEBUG verlassen mit automatischem Neuaufaufruf
von MDEBUG falls DOS nicht aktiv ist.
<F1> - Aufruf der Online-Hilfe
Die Online-Hilfe besteht aus zwei Seiten, wobei die Seite mit der
Beschreibung der Statuszeilen teilweise kontext-sensitiv ist.
(will sagen: Die in der Online-Hilfe angezeigte Statuszeile ent-
spricht der normalen Statuszeile). Die aktuelle Seite der Online-
Hilfe kann über die Taste <RETURN> gewechselt werden, die Taste
<ESC> beendet die Online-Hilfe. Die Schalter und Variablen des
Disassemblers können auch direkt während der Anzeige der zweiten
Seite der Online-Hilfe geändert werden.
Die zweite Seite der Online-Hilfe kann auch direkt über die Taste
<O> aufgerufen werden.
Falls die Online-Hilfe über die Taste <F10> verlassen wird, wird
der Aufruf des Disassemblers und MDEBUGs sofort beendet.
<ALT-L> - nochmalige Anzeige der letzten Meldung
<CTRL-PgUp>, <CTRL-PgDn>
- verschieben des Windows des Disassemblers um eine
Zeile nach oben bzw. unten
<CTRL-End>, <CTRL-Home>
- verschieben des Windows in den unteren bzw. oberen
Bildschirmbereich.
<ALT-F9> - Neuaufbau des Windows
────────────────────────────────────────────────────────────────────────────────
Seite 33
<CTRL-F1>
Die Taste <CTRL-F1> schließt das Window des Disassemblers und
restauriert den Bildschirm unter dem Window. Nach dem Betätigen
einer Taste wird das Window des Disassemblers wieder geöffnet.
<ALT-1> .. <ALT-9>
Setze Marker # auf die Adresse in der aktuellen Zeile
Falls auf einer Adresse ein Marker steht, wird vor der Zeile auf
dem Rahmen die Nummer des Markers in der Farbe 2 angezeigt.
Sind auf einer Adresse mehrere Marker gesetzt, so wird immer nur
der Marker mit der kleinsten Nummer angezeigt.
Da zur Überprüfung, ob auf einer Adresse ein Marker steht, die
Adressen normalisiert werden, sind die einzelnen Werte des Seg-
ments und Offsets unerheblich - wesentlich ist nur die Adresse
die sich aus diesen beiden Werten ergibt.
Da die Marker 1 und 2 für die Sicherung von Speicherbereichen in
eine Datei bzw. für den Ausdruck von Speicherbereichen benutzt
werden (s.u.), sollten soweit möglich nur die Marker von 3 bis
9 zur Markierung von Adressen benutzt werden.
Nach dem Programmstart sind alle Marker gelöscht.
<1> .. <9>
Springe zum Marker #. Es können nur schon gesetzte Marker ange-
sprungen werden.
<ALT-0> - Lösche alle Marker
────────────────────────────────────────────────────────────────────────────────
Seite 34
Suchen von Referenzen
─────────────────────
Bei der Disassemblierung von unbekannten Code ist es häufig nötig
zu wissen, wann auf eine Speicherstelle zugegriffen wird bzw.
wann eine Routine aufgerufen wird.
Für diese Aufgaben besitzt der Disassembler folgende Funktionen:
<F8>
Suche eine Code-Referenz (z.B. 'jmp n', 'int n', 'jc nn', etc.)
auf eine beliebige Adresse ab der Adresse in der aktuellen Zeile.
<SHIFT-F8>
Suche eine Daten-Referenz (z.B. 'mov ax,[nn]', 'inc [nn]', etc.)
auf eine beliebige Adresse ab der Adresse in der aktuellen Zeile.
In beiden Fällen kann als Adresse, auf die eine Referenz gesucht
werden soll, eine beliebige Kombination aus Segment und Offset
eingegeben werden. Beachtet werden muß, daß bei der Suche nach
einer Daten-Referenz der eingegebene Wert für das Segment igno-
riert wird.
Gesucht wird immer nur bis zum Ende eines Segments. Die Suche
kann jederzeit über die Taste <ESC> abgebrochen werden. Falls
die Suche abgebrochen oder keine Referenz gefunden wurde, kann
direkt nach der Suche über die Taste <0> die letzte überprüfte
Adresse ermittelt werden. Wird eine Referenz gefunden, wird der
Code ab dem gefundenen Befehl im Disassembler angezeigt (und die
Taste <0> behält ihre ursprüngliche Funktion).
Während der Suche zeigt der Disassembler zur optischen Kontrolle
jeweils den Code, den er gerade überprüft, an.
<CTRL-F8>
Letzte Suche fortsetzen.
Gesucht wird die zuletzt gesuchte Adresse mit dem zuletzt angege-
benen Referenz-Art (Code/Data) ab dem auf den zuletzt gefundenen
Befehl folgenden Befehl (d.h. nicht ab dem aktuellen Befehl!).
Diese Funktion ist nur möglich, falls vorher mindestens einmal
eine Daten- oder Code-Referenz gesucht wurde.
────────────────────────────────────────────────────────────────────────────────
Seite 35
Benutzung des Adressen-Stacks
─────────────────────────────
Zum bequemen Verfolgen des Programmflußes, besitzt der Dis-
assembler einen Adressen-Stack.
Der Adressen-Stack ist als Ring-Puffer organisiert und kann bis
zu 25 Einträge aufnehmen. Die aktuelle Anzahl der Adressen auf
dem Adressen-Stack wird immer in der Statuszeile angezeigt.
[siehe Abb. 3a und 3b]
In der auf die Statuszeile folgenden Zeile werden immer die
obersten 7 Elemente des Adressen-Stacks angezeigt.
Zur Manipulation des Adressen-Stacks stehen folgende Tasten zur
Verfügung:
<Insert> pusht die Adresse des Speicherbereichs aus der aktuellen
Zeile auf den Adressen-Stack. <Delete> löscht die oberste Adresse
vom Adressen-Stack und <CTRL-D> löscht den gesamten Adressen-
Stack.
<CursorRight> popt die oberste Adresse vom Adressen-Stack und
übernimmt diese als neue Start-Adresse für den Disassembler. Der
aktuelle Anzeige-Modus des Disassemblers und die aktuelle Zeile
werden entsprechend den für die Adresse gespeicherten Daten
korrigiert.
Es ist ebenfalls möglich, jede Adresse vom Adressen-Stack als
neue Start-Adresse zu nehmen, ohne diese vom Adressen-Stack zu
entfernen.
Dazu dienen die Tasten <Tab> und <SHIFT-Tab>. Nach dem Betätigen
einer dieser beiden Tasten befindet sich der Disassembler im
Scrollstackmodus, in welchem über die Tasten <Tab>, <SHIFT-Tab>,
<CursorLeft>, <CursorRight>, <Home> und <End> eine Adresse vom
Adressen-Stack gewählt werden kann.
In diesem Modus wird die Anzahl der Elemente auf dem Adressen-
Stack in der letzten Zeile des Windows angezeigt und in der
Statuszeile wird immer die Nummer des aktuellen Stack-Elements
angezeigt. Im Scrollstackmodus werden in den oberen 10 Zeilen
immer der Code bzw. die Daten der aktuellen Stack-Adresse ange-
zeigt. (Falls dies nicht erwünscht ist, muß der Modus über die
Taste <SHIFT-Tab> aufgerufen werden.)
────────────────────────────────────────────────────────────────────────────────
Seite 36
Verlassen werden kann der Modus über die Tasten <RETURN> oder
<ESC>. Wird der Modus über <RETURN> verlassen, so übernimmt der
Disassembler die aktuelle Adresse vom Adressen-Stack (also die,
die ganz links in der Farbe 2 angezeigt wird) als neue Start-
Adresse und ändert den aktuellen Anzeige-Modus und die aktuelle
Zeile entsprechend der neuen Adresse. Abgebrochen werden kann der
Scrollstackmodus über die Taste <ESC>.
Die Funktion 'Folge dem Befehl'
───────────────────────────────
Zusätzlich besitzt der Disassembler die Möglichkeit mit der Taste
<CursorLeft> dem aktuellen Befehl zu 'folgen'.
Dies bedeutet im Disassembler- und im Assembler-Modus:
Falls der Befehl in der aktuellen Zeile einen explizit angege-
benen Speicheroperanden enthält, wird die Adresse des Befehls aus
der Zeile auf den Adressen-Stack gepusht und die Adresse des
Operanden aus dem Befehl als neue Start-Adresse genommen.
Falls der Speicheroperand in der aktuellen Zeile zusätzlich über
ein Index- oder ein Basisregister adressiert wird, wird auf den
Offset der neuen Start-Adresse noch der Inhalt des Registers 'HB'
aufaddiert (ohne Berücksichtigung eines Überlaufs). D.h. das
Register 'HB' repräsentiert, je nach Adressierung des Operanden,
eines oder mehrere der Registers SI, DI, BP oder BX.
Beispiele:
┌───────────────────┬─────────────────────────────────────────────┐
│ │ Adresse für die Funktion 'Folge dem Befehl' │
│ Befehl │ (Register 'HB' enthalte den Wert 1000h) │
╞═══════════════════╪═════════════════════════════════════════════╡
│ ES: MOV AX,[0400] │ ES:0400 │
│ SS: INC W[0100] │ SS:0100 │
│ MOV AX,[BX+0500] │ DS:1500 │
│ INC [BP] │ SS:1000 │
│ MOV [BP+SI],0100 │ SS:1000 │
└───────────────────┴─────────────────────────────────────────────┘
Die Funktion 'Folge dem Befehl' kann auch auf alle Befehle mit
einem expliziten oder impliziten Sprungziel angewendet werden. In
diesem Fall ermittelt der Disassembler die neue Start-Adresse
analog der Vorgehensweise des Prozessors. Außerdem wird in diesem
Fall nicht die Adresse des Befehls in der aktuellen Zeile,
sondern die Adresse des Befehls in der folgenden Zeile auf den
Adressen-Stack gesichert. Der Inhalt des Hilfsregisters 'HB'
wird hierbei auf keinem Fall berücksichtigt.
────────────────────────────────────────────────────────────────────────────────
Seite 37
Das Segment der neuen Start-Adresse wird in allen Fällen analog
zur Vorgehensweise des Prozessors ermittelt.
Das Segment für die neue Start-Adresse ist entweder
■ der Inhalt des Segment-Registers DS
- bei Befehlen mit Speicheroperanden für deren Adressierung
NICHT das Register BP verwendet wird
Beispiel: 'MOV BX,W[0012]' oder 'INC B[DI+04]'
■ der Inhalt des Segment-Registers SS
- bei Befehlen mit Speicheroperanden, die u.a. durch das
Register BP addressiert werden
Beispiel: 'MOV BX,W[BP+0012]'
■ der Inhalt des Segment-Registers CS
- bei direkten intrasegment JMP- und CALL-Befehlen
Beispiel: 'JMP 04566'
■ direkt im Befehl enthalten
- bei direkten intersegment JMP- und CALL-Befehlen
Beispiel: 'CALL 04455:0044'
oder
■ implizit im Befehl enthalten
- bei Befehlen zum Aufruf eines Interrupts
Beispiel: 'INT 021', aber auch bei den Befehl
'INTO' (Interrupt 4)
Segment-Prefixe in der aktuellen Zeile werden vom Disassembler
bei der Ermittlung des Segments der neuen Start-Adresse ebenfalls
berücksichtigt - falls sie auch vom aktuellen Prozessor berück-
sichtigt würden.
Der Anzeige-Modus des Disassemblers wird automatisch der Art des
Speicherzugriffs des Befehls aus der aktuellen Zeile angepasst.
Die Funktion 'Folge dem Befehl' kann im Disassembler-Modus auf
folgende Anweisungen angewendet werden:
■ direkte JMP- und CALL-Befehle
■ Befehle mit impliziten Sprungziel
■ Befehle mit expliziten Speicheroperanden
■ ESC-Befehle, bei denen im 'mod r/m'-Byte die Adresse eines
Speicheroperanden codiert ist - d.h. Coprozessor-Befehle mit
einem Speicheroperanden die von der aktuellen Ziel-CoCPU
nicht erkannt werden.
────────────────────────────────────────────────────────────────────────────────
Seite 38
■ Da der Disassembler bei Befehlen, mit denen ein expliziter Wert
in ein Wort-Register geladen wird, nicht entscheiden kann, ob
es sich hierbei um eine Konstante oder einen Offset handelt,
kann die Funktion 'Folge dem Befehl' auch auf diese Befehle
angewendet werden.
Ob die Funktion 'Folge dem Befehl' auf den aktuellen Befehl
anwendbar ist, ist auch an der vorletzten Zeile erkennbar. Falls
diese leer ist, ist die Funktion nicht anwendbar.
Der aktuelle Modus zur Anzeige von Displacements und Offsets ist
für die Funktion 'Folge dem Befehl' bedeutungslos.
Im Dump-Modus ist die Funktion 'Folge dem Befehl' in jeder Zeile
möglich. Hier richtet sich die neue Start-Adresse des Disassemb-
lers nach der Anwendung dieser Funktion nach den aktuellen Wert
des Schalters 'DumpLineMode':
┌───────────┬─────────────┬──────────────────────────────────────┐
│ Wert des │ neuer │ Neue Start-Adresse │
│ Schalters │ Modus │ Segment │ Offset │
╞═══════════╪═════════════╪════════════════════╪═════════════════╡
│ DD │ Dump │ 2. Wort in der │ 1. Wort in der │
│ │ │ aktuellen Zeile │ aktuellen Zeile │
├───────────┼─────────────┼────────────────────┼─────────────────┤
│ DW │ Dump │ Register DS │ 1. Wort in der │
│ │ │ │ aktuellen Zeile │
├───────────┼─────────────┼────────────────────┼─────────────────┤
│ AD │ Disassemble │ 2 Wort in der │ 1. Wort in der │
│ │ /Assemble │ aktuellen Zeile │ aktuellen Zeile │
├───────────┼─────────────┼────────────────────┼─────────────────┤
│ AW │ Disassemble │ Register DS │ 1. Wort in der │
│ │ /Assemble │ │ aktuellen Zeile │
└───────────┴─────────────┴────────────────────┴─────────────────┘
Der Wert des Schalters 'DumpLineMode' wird (nur) im Dump-Modus in
der Statuszeile angezeigt. [siehe Abb. 3b]
Er kann über die Taste <CTRL-F3> umgeschaltet werden.
Die Funktion 'Folge dem Befehl' kann in allen Anzeige-Modi auch
über die Tasten <ALT-CursorLeft> oder <Backspace> aufgerufen
werden. In diesem Fall wird die aktuelle Adresse vor der Anzeige
des neuen Speicherbereichs aber NICHT auf dem Adressen-Stack
gespeichert.
────────────────────────────────────────────────────────────────────────────────
Seite 39
Die Schalter des Disassemblers
──────────────────────────────
Die Ausgabe und das Verhalten des Disassemblers können auch über
mehrere Schalter verändert werden.
Die aktuellen Werte der wichtigsten Schalter werden immer in der
Statuszeile angezeigt. [siehe Abb. 3a und 3b]
Anzeige-Modi für Offsets und Displacements
──────────────────────────────────────────
Normalerweise konvertiert der Disassembler alle relativen Dis-
placements in JMP- und CALL-Befehlen zu absoluten Werten. Da dies
nicht immer erwünscht ist, kann er diese auch als zum aktuellen
Instruktion-Pointer relative Offsets ausgeben. [siehe Abb. 8]
────────────────────────────────────────────────────────────────────────────────
╔══ MDDISDRV V2.05 ══════ Ziel-CPU: V20/----- ══[inst. CPU: V20/-----]═════╗
║ 3484:014D FA CLI [ 8086]+ ║
->║ 3484:014E 2E 3A 26 37 01 CS: CMP AH,B[$-0018] ABS: 0137 [ 8086]+ ║
║ 3484:0153 75 3A JNZ $+003C ABS: 018F [ 8086]+ ║
║ 3484:0155 3C 00 CMP AL,00 ; = 0 = 0000_0000xB [ 8086]+ ║
║ 3484:0157 75 05 JNZ $+0007 ABS: 015E [ 8086]+ ║
║ 3484:0159 E8 AE 00 CALL $+00B1 ABS: 020A [ 8086]+ ║
║ 3484:015C EB 31 JMP $+0033 ABS: 018F [ 8086]+ ║
║ 3484:015E 2E 80 3E 40 01 00 CS: CMP B[$-001F],00 ABS: 0140 [ 8086]+ ║
║ 3484:0164 74 29 JZ $+002B ABS: 018F [ 8086]+ ║
║ 3484:0166 3C 01 CMP AL,01 ; = 0 = 0000_0001xB [ 8086]+ ║
╟─ akt. Stack-Element: 0 ── Disp. Code: R Daten: R ─[BPuWRfapK]──[lpt1, 55]───╢
║ ║
╟─ Register: CS: 3484 DS: 3484 ES: 3484 SS: 3484 GS: 0000 FS: 0000 HB: 0000 ──╢
╠══seg:off══╤ +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F ╤0123456789ABCDEF╣
║ 3484:0137 │ D1 09 12 90 23 32 0E 90-23 FF 33 02 4D 02 54 02 │╤..É#2.É# 3.M.T.║
║ < Tastenbelegung > ║
╚══════════════════════[ (c) 1991 - 1992 Bernd Schemmer ]══════════════════════╝
────────────────────────────────────────────────────────────────────────────────
Abb. 8 - Anzeige im Disassembler-Modus mit relativer Angabe aller
Offsets und Displacements
────────────────────────────────────────────────────────────────────────────────
Seite 40
Der Wert des Instruktion-Pointers wird in diesem Modus durch das
Zeichen '$' repräsentiert. Der Wert des Instruktion-Pointers ist
immer der Offset des ersten Bytes des JMP- oder CALL-Befehls.
Segment-Prefixe werden nicht berücksichtigt. (Dies entspricht der
Philosophie des Assemblers A86, s.u.).
Zur Information wird der Absolut-Wert der Adresse in diesem Modus
als Kommentar hinter dem Befehl ausgegeben (aber nur, falls noch
genügend Platz in der Zeile vorhanden ist).
Hinweis: Die Displacements in den Opcodes sind immer relativ zum
ersten Byte der folgenden Instruktion bzw. zum ersten
Prefix der folgenden Instruktion falls vorhanden.
Die Offsets von Speicheroperanden, deren Adresse ohne Basis- oder
Index-Register angegeben ist, können ebenfalls als relative
Offsets ausgegeben werden. [siehe Abb. 8]
Der Modus für die Anzeige von Offsets kann einzeln für Offsets
von Speicheroperanden und für Displacements geändert werden. Der
aktuelle Modus wird im Disassembler- oder Assembler-Modus immer
in der Statuszeile angezeigt. Geändert werden kann er über die
Taste <ALT-F3>. Durch mehrmaliges Betätigen der Taste <ALT-F3>
können alle möglichen Kombinationen eingestellt werden.
Der Schalter B
Der Schalter B bestimmt, ob vor der Funktion 'Folge dem Befehl'
die aktuelle Adresse automatisch auf den Adressen-Stack gepusht
wird (Wert 'B') oder nicht (Wert 'b').
Der Schalter kann über die Taste <CTRL-B> umgeschaltet werden.
Falls der Schalter auf 'b' steht ist, ist die Wirkung der Tasten
<CursorLeft>, <ALT-CursorLeft> und <Backspace> äquivalent und die
Taste <CursorRight> ist gesperrt.
Der Schalter P
Der Schalter P bestimmt, ob Prefixe vor dem aktuellen Befehl
(Wert 'P') oder als einzelne Befehle ausgegeben werden.(Wert 'p')
Der Schalter kann über die Taste <CTRL-P> umgeschaltet werden.
Beachtet werden muß, daß Segment-Prefixe von der Funktion 'Folge
dem Befehl' NICHT berücksichtigt werden, falls Prefixe als
einzelne Befehle ausgegeben werden.
────────────────────────────────────────────────────────────────────────────────
Seite 41
Der Schalter U
Der Schalter U bestimmt, ob der Disassembler bei unbekannten
Opcodes nur ein Byte (Wert 'u') oder 2 Byte (= 1 Wort, Wert 'U')
als unbekannten Befehl interpretiert.
Der Schalter kann über die Taste <CTRL-U> umgeschaltet werden.
Der Schalter R
Der Schalter R bestimmt, ob die Anzeige im Dump-Modus kontinu-
ierlich upgedatet werden soll (Wert 'R') oder nicht (Wert 'r').
Der Schalter kann über die Tasten <CTRL-R> oder <F9> umgeschaltet
werden.
Der Schalter W
Der Schalter W bestimmt, ob WAIT-Befehle vor Coprozessor-Befehlen
bei einer Ziel-CoCPU ab dem 80287 als Teil des Coprozessor-
Befehls (Wert 'w') oder als einzelne Befehle angesehen werden
(Wert 'W').
Der Schalter kann über die Taste <CTRL-W> umgeschaltet werden.
WAIT-Befehle sind für Coprozessoren ab dem 80287 eigentlich nicht
mehr nötig. Falls als Ziel-CoCPU ein 8087 angegeben ist, werden
WAIT-Befehle immer als Teil des Coprozessor-Befehls angesehen.
Der Schalter A
Der Schalter A bestimmt, ob beim Sichern von Speicherbereichen
vorhandene Dateien überschrieben (Wert 'a') oder verlängert (Wert
'A') werden.
Der Schalter gilt auch für virtuelle Drucker! (s.u.)
Der Schalter kann über die Taste <CTRL-A> umgeschaltet werden.
Der Schalter F
Der Schalter F bestimmt, ob Dateien bzw. Ausdrucke formatiert
(Wert 'F') werden oder nicht (Wert 'f').
Der Schalter kann über die Taste <CTRL-F> umgeschaltet werden.
────────────────────────────────────────────────────────────────────────────────
Seite 42
Der Schalter L
Durch den Schalter L kann der vom Disassembler verwendete Algo-
rithmus zur Ermittlung des vorherigen Befehls beim Rückwärts-
scrollen bestimmt werden.
Hierfür stehen 3 Möglichkeiten zur Verfügung:
1. Der Disassembler sucht den längsten Befehl vor der Start-
Adresse (Wert 'l')
2. Der Disassembler sucht den kürzesten Befehl vor der Start-
Adresse (Wert 's')
3. Der Disassembler ermittelt den Befehl vor der Start-
Adresse seitenweise (Wert 'p')
In diesem Modus wird vom Offset der Start-Adresse 32
subtrahiert und von dieser Adresse dann nach vorne dis-
assembliert bis der Befehl vor der Start-Adresse erreicht
ist.
Der Schalter kann über die Taste <CTRL-L> geändert werden.
Je nach der Art des aktuellen Codes kann einer der 3 Algorithmen
der Beste sein. Falls es sich z.B. um überwiegend kürzere Opcodes
handelt, ist der Algorithmus 2 zu wählen, handelt es sich aber
um überwiegend längere Opcodes, so ist der Algorithmus 1 vorzu-
ziehen. Im allgemeinen sollte die Algorithmus 3 die besten Ergeb-
nisse liefern.
Falls kein korrekter Befehl vor der Start-Adresse gefunden wird,
wird die Start-Adresse in allen drei Modi um 2 vermindert.
Sollte der Disassembler beim Rückwärts-Scrollen den Anfang eines
Befehls nicht korrekt erkennen, kann über die Tasten <+> bzw.
<CTRL-CursorDown> und <-> bzw. <CTRL-CursorUp> der Offset der
Start-Adresse in 1-Byte-Schritten korrigiert werden.
────────────────────────────────────────────────────────────────────────────────
Seite 43
Der Schalter K
Der Schalter K legt fest, ob Kommentare ausgegeben werden sollen
(Wert: 'K') oder nicht (Wert: 'k').
Falls der Schalter K auf 'k' steht werden folgende Kommentare
NICHT ausgegeben:
- unbekannte Opcodes im binären Format
- die Felder von unbekannte ESC-Opcodes im binären Format
- der Wert von immediate Bytes in dezimalen, binärem und ASCII-
Format
- der Wert von immediate Words in dezimalen Format
- das Ziel für Verzweigungsbefehle
Der Schalter kann über die Taste <CTRL-K> umgeschaltet werden.
Der Schalter Q
Über den Schalter Q können die akustischen Ausgaben des Disassem-
blers ein- bzw. ausgestellt werden. Der Wert des Schalters
wird nicht angezeigt.
────────────────────────────────────────────────────────────────────────────────
Seite 44
Sichern von Speicherbereichen
─────────────────────────────
Allgemeines zum Sichern von Speicherbereichen
─────────────────────────────────────────────
Der Disassembler kann auch Speicherbereiche in verschiedenen
Formaten in einer Datei sichern oder ausdrucken.
Da die Ausgabe von Speicherbereichen in eine Datei bzw. der Aus-
druck über das Betriebssystem durchgeführt wird, darf hierfür DOS
nicht aktiv sein.
Der Disassembler überprüft deshalb vor der Ausgabe, ob DOS aktiv
ist. Ist dies der Fall, wird eine Fehlermeldung ausgegeben und
die Funktion abgebrochen. In diesem Fall sollte der Disassembler
über die Taste <ALT-F5> verlassen werden und nach dem automa-
tischen Neuaufruf von MDEBUG sobald DOS nicht aktiv ist die Funk-
tion nochmal aufgerufen werden.
Gesichert bzw. gedruckt wird immer der Speicherbereich zwischen
den Markern 1 und 2. Diese müssen daher vorher gesetzt werden. Da
maximal ein Segment auf einmal gesichert bzw. ausgedruckt werden
kann, müssen die Marker 1 und 2 zudem denselben Wert für das
Segment besitzen.
Eine bestehende Datei wird, je nach dem Wert des Schalters A,
überschrieben oder verlängert. Ob eine neue Datei erstellt oder
eine bestehende Datei verlängert wird, ist auch aus den Meldungen
des Disassemblers während und nach dem Bearbeiten der Datei
ersichtlich. Jede Datei-Ausgabe und jeder Ausdruck wird mit einem
Header versehen.
Falls der Schalter F auf 'F' steht, wird die Datei-Ausgabe bzw.
der Ausdruck seitenweise formatiert. Die maximale Anzahl Zeilen
pro Seite für die Seitenformatierung wird in der Statuszeile
angezeigt; sie kann über die Tasten <>>, <<> und <#> verändert
werden. <<> vermindert die aktuelle Anzahl um 5, <>> erhöht die
aktuelle Anzahl um 5 und <#> erhöht die aktuelle Anzahl um 1.
Während des Bearbeitens einer Datei bzw. des Ausdrucks wird in
der letzten Zeile des Windows eine Laufzeitanzeige ausgegeben.
Die Dateiausgabe bzw. der Ausdruck kann jederzeit über die Taste
<ESC> abgebrochen werden.
────────────────────────────────────────────────────────────────────────────────
Seite 45
Alle Fehler (auch Hardware-Fehler) beim Sichern bzw. Ausdruckens
eines Speicherbereichs werdem vom Disassembler abgefangen. Ein
Fehler führt immer zum Abbruch der Funktion.
Nach dem Ende der Dateibearbeitung bzw. des Ausdrucks wird eine
Meldung über den Erfolg oder Mißerfolg der Bearbeitung inclusive
des Offsets des ersten Bytes nach dem letzten bearbeitenden Byte
ausgegeben. Falls ein DOS-Fehler aufgetreten ist, wird auch die
Nummer des DOS-Fehlers angezeigt.
Möglich sind folgende (DOS-)Fehlernummern:
┌────────┬─────────────────────────────────────┐
│ Nummer │ Bedeutung │
├────────┼─────────────────────────────────────┤
│ 03h │ Pfad nicht gefunden │
│ 04h │ Keine freies Handle mehr vorhanden │
│ 05h │ Zugriff abgelehnt │
│ 0Ch │ Fehlerhafter Zugriffsmodus │
│ 13h │ Diskette ist schreibgeschützt │
│ 15h │ Laufwerk nicht bereit │
├────────┼── Erweiterungen der Fehlernummern ──┤
│ FFFEh │ Drucker nicht bereit │
│ FFFFh │ Diskette ist voll │
└────────┴─────────────────────────────────────┘
Unter besonderen Umständen können möglicherweise auch andere DOS-
Fehler auftreten.
Eine eventuell nur teilweise erstellte Datei wird nicht gelöscht.
Beachtet werden muß, daß der Disassembler für die Dateibearbei-
tung und den Ausdruck das PSP des von MDEBUG unterbrochenen
Prozesses benutzt.
────────────────────────────────────────────────────────────────────────────────
Seite 46
Sichern von Speicherbereichen in eine Datei
───────────────────────────────────────────
Speicherbereiche können im Disassembler in verschiedenen Formaten
in eine Datei gesichert werden.
Der Name für die Datei setzt sich dabei folgendermaßen zusammen:
────────────────────────────────────────────────────────────────────────────────
┌───────────────────────────────────────────────────────────────┐
│ │
│ ┌─ Offset des 1. Bytes des zu sichernden │
│ │ Speicherbereichs in hexadezimalem Format │
│ ┌┴─┐ │
│ ssssoooo.xxx │
│ └┬─┘ └┬┘ │
│ │ │ │
│ │ └── Typ der zu erstellenden/verlängernden Datei, │
│ │ folgende Typen sind möglich: │
│ │ DIS - die Datei enthält disassemblierten Code │
│ │ DMP - die Datei enthält einen Speicherdump │
│ │ DAT - die Datei enthält 'db'-Befehle für einen │
│ │ Speicherbereich │
│ │ │
│ └─ Segment des zu sichernden Speicherbereichs im │
│ hexadezimalem Format │
│ │
└───────────────────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Abb. 9 - Aufbau eines Dateinamens
Die Datei wird immer im aktuellen Directory erstellt.
Zur Sicherung eines Speicherbereichs stehen folgende Tasten zur
Verfügung:
Die Taste <F6> veranlasst den Disassembler den Speicherbereich
zwischen den Markern 1 und 2 als disassemblierten Code in eine
Datei zu sichern.
Je nach aktuellem Modus geschieht dies im Disassembler- oder im
Assembler-Modus. Der Aufbau der Zeilen der Datei ist dabei analog
dem Aufbau der Zeilen im entsprechenden Modus im Window (ausge-
nommen die Richtungspfeile für Sprungbefehle, die nicht mit aus-
gegeben werden.)
Im Assembler-Modus werden zudem alle Header als Kommentare in die
Datei geschrieben.
────────────────────────────────────────────────────────────────────────────────
Seite 47
Die Taste <SHIFT-F6> führt zur Sicherung des Speicherbereichs
zwischen den Markern 1 und 2 als Speicherdump in eine Datei. Auch
hier entspricht der Aufbau der Zeilen in der Datei dem Aufbau der
Zeilen im Window im Dump-Modus.
Die Taste <CTRL-F6> veranlasst den Disassembler den Speicher-
bereich zwischen den Markern 1 und 2 über 'db'-Befehle in eine
Datei zu schreiben. [siehe Abb. 10]
────────────────────────────────────────────────────────────────────────────────
┌── Befehl ┌──Kommentar
┌───┴────────────────────────────────────────────────────────────┐ ┌┴───────┐
db 0FA,02E,03A,026,037,001,075,03A,03C,000,075,005,0E8,0AE,000,0EB ;3484:014D
┌─ ┌────────────────────────────────────────────────────────────── ┌────────
│ │ ┌───────────────────────────────────┘
│ │ └─ Adresse des Speicherbereichs als Kommentar
│ │
│ └── max. 16 Byte ab der angegebenen Adresse im hexadezimalen Format
└──── Assembler-Befehl 'DB'
────────────────────────────────────────────────────────────────────────────────
Abb. 10 - Aufbau der Zeilen einer .DAT-Datei
Erstellen von Quelldateien für den A86
──────────────────────────────────────
Falls der Disassembler im Assembler-Modus ist und mindestens die
Displacements von JMP- und CALL-Befehlen relativ zum IP ausgege-
ben werden, kann die so erstellte Datei ohne Änderungen vom A86
übersetzt werden.
Einschränkungen hierbei:
■ Bei Befehlen, die auf Speicheroperanden zugreifen, muß jeweils
der angegebene Offset überprüft werden.
■ Befehle, die nur auf einem oder mehreren Prozessoren möglich
sind (gekennzeichnet durch '*' bzw. '+*') müssen jeweils über-
prüft werden.
────────────────────────────────────────────────────────────────────────────────
Seite 48
■ Falls WAIT-Befehle als einzelne Befehle ausgegeben werden und
Coprozessorbefehle im zu sichernden Speicherbereich vorkommen,
muß in die erstellte Datei noch die Assembler-Direktive
'.287 '
eingefügt werden.
Ansonsten fügt der A86 zusätzliche unnötige WAIT-Befehle ein.
■ Die neuen Befehle des 80386 (incl. des undokumentierten Befehls
LOADALLD) beherrscht der A86 nicht. Diese müssen von Hand zu
'db'-Statements umcodiert oder über eine Macro-Datei definiert
werden.
■ Der Befehl 'LOADALL' (Opcode: 0F 05) des 80286 und der Befehl
'FFREEP i' (Opcode DF r/m) des 80287 sind dem A86 ebenfalls
nicht bekannt.
■ Beachtetet werden muß auch:
Die vom A86 aus der Quelldatei erstellte Objektdatei ist zwar
von der Funktion her identisch mit dem disassemblierten Code.
In der Datei können aber andere Opcodes als im disassemblierten
Speicherbereich enthalten sein.
Dies hat zwei Gründe:
Zum einen optimiert der A86 beim Compilieren; so ersetzt er
z.B. den Befehl 'LEA AX,[BX]' durch den schnelleren Befehl
'MOV AX,BX'. Und zum anderen ist der Befehlssatz der 80x86-
Prozessoren redundant, d.h. für mehrere Befehle existieren
verschiedene Opcodes.
So kann (z.B.) der Befehl 'MOV AX,W[01200]' als 'A1 00 12' oder
als '8B 06 00 12' codiert werden.
────────────────────────────────────────────────────────────────────────────────
Seite 49
Ausgabe von Speicherbereichen auf den Drucker
─────────────────────────────────────────────
Der Disassembler kann Speicherbereiche auch direkt auf den
Drucker ausgeben. Da hierfür ebenfalls die DOS-Funktionen benutzt
werden, müssen die Anmerkungen unter 'Allgmeines zum Sichern von
Speicherbereichen' beachtet werden.
Der aktuelle Drucker für die Ausgabe kann über die Taste <ALT-P>
zwischen LPT1, LPT2, LPT3 usw. bis LPT9 gewählt werden.
Der aktuelle Drucker wird in der Statuszeile angezeigt.
Zum Drucken können folgende Tasten verwendet werden:
Die Taste <F7> führt zum Ausdruck des disassemblierten Codes
zwischen den Markern 1 und 2. Je nach dem aktuellen Modus wird
dabei der Zeilenaufbau der Zeilen im Disassembler-Modus oder im
Assembler-Modus benutzt.
Die Taste <SHIFT-F7> führt zum Ausdruck des Speicherbereichs
zwischen den Markern 1 und 2 als Dump. Auch hier entspricht der
Aufbau der gedruckten Zeilen dem Aufbau der Zeilen im Window im
Dump-Modus.
Über die Taste <CTRL-F7> kann der Speicherbereichs zwischen den
Markern 1 und 2 als 'db'-Befehle ausgedruckt werden. Der Aufbau
der Zeilen ist dabei analog zur Ausgabe der Taste <CTRL-F6>.
Beachtet werden muß aber folgendes:
Falls der aktuelle Drucker z.B. 'LPT4' ist, für LPT4 aber kein
Einheitentreiber existiert, erstellt DOS eine Datei mit dem
Namen LPT4 im aktuellen Directory. Hierbei gelten dann alle
Bedingungen wie bei der Ausgabe in eine Datei (mit Ausnahme der
Wahl des Dateinamens, s.o.).
Da für LPT4 bis LPT9 in den meisten Systemen kein Einheiten-
Treiber vorhanden ist, können diese deshalb als virtuelle Drucker
benutzt werden (falls der Schalter A auf 'A' steht).
Eine weitere Einschränkung ist folgende:
Der Disassembler überprüft mit den IOCTL-Funktionen 0 und 7 des
Interrupts 21h ob der angesprochene Drucker zur Ausgabe bereit
ist. Verschiedene Einheitentreiber für Drucker erkennen aber
nicht korrekt ob ein betriebsbereiter Drucker vorhanden ist. Der
Disassembler gibt in diesem Fall eine Erfolgs-Meldung aus obwohl
keine Ausgabe erfolgte.
────────────────────────────────────────────────────────────────────────────────
Seite 50
Zusammenfassung der Tastenbelegung im Disassembler
──────────────────────────────────────────────────
┌────────────────────┬─────────────────────────────────────┐
│ Taste(n) │ Bedeutung │
╞════════════════════╪═════════════════════════════════════╡
│ <F1> │ akt. Seite der Online-Hilfe anzeigen│
│ <O> │ 2. Seite der Online-Hilfe anzeigen │
│ │ │
│ <CursorDown> │ │
│<CursorUp> <Blank> │ Speicherbereich scrollen │
│<PgDn> <PgUp> <CR> │ Speicherbereich scrollen │
│<+> <CTRL-CursorUp> │ Offset um 1 Byte erhöhen │
│<-><CTRL-CursorDown>│ Offset um 1 Byte vermindern │
│ <A> │ Offset um 2 Byte vermindern │
│ <W> │ Offset um 2 Byte erhöhen │
│ <0> │ zur letzten Position springen │
│ <J> <F4> │ neue Start-Adresse eingeben │
│ <I> │ Interrupt-Routine disassemblieren │
│ <CTRL-N> │ Start-Adresse normalisieren │
│ │ │
│ <ALT-0> │ alle Marker löschen │
│ <ALT-1> ... │ │
│ <ALT-9> │ Marker # setzen │
│ <1> ... <9> │ Marker # anspringen │
│ │ │
│ <CTRL-T> │ akt. Zeile zur ersten Zeile machen │
│ <Home> │ zur ersten Zeile des Windows │
│ <End> │ zur letzten Zeile des Windows │
│ │ │
│ <Delete> │ oberste Stack-Adresse löschen │
│ <CTRL-D> │ gesamten Adressen-Stack löschen │
│ <Insert> │ akt. Adresse auf den Stack pushen │
│ <SHIFT-Tab> <Tab> │ Stackzeile scrollen │
│ <CursorRight> │ neue Start-Adresse vom Stack popen │
│ <CursorLeft> │ Befehl folgen mit vorherigen push │
│ <ALT-CursorLeft> │ Befehl folgen (ohne Push) │
│ <Backspace> │ Befehl folgen (ohne Push) │
│ │ │
│ <F2> │ Ziel-CPU ändern │
│ <SHIFT-F2> │ Ziel-CoCPU ändern │
│ <F3> │ Anzeige-Modus ändern │
└────────────────────┴─────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 51
┌────────────────────┬─────────────────────────────────────┐
│ Taste(n) │ Bedeutung │
╞════════════════════╪═════════════════════════════════════╡
│ <CTRL-F3> │ Anzeige-Modus für die letzten beiden│
│ │ Zeilen im Dump-Modus ändern │
│ <SHIFT-F3> │ Assembler-Modus ein/ausschalten │
│ <ALT-F3> │ Displacement-Modus ändern │
│ <CTRL-B> │ Stackblocking ein/ausschalten │
│ <CTRL-L> │ Modus für die Ermittlung der │
│ │ vorherigen Instruktion umschalten │
│ <CTRL-P> │ Prefixmodus wechseln │
│ <CTRL-U> │ Modus für unbekannte Opcodes ändern │
│ <CTRL-W> │ Modus für WAIT-Befehle bei │
│ │ Coprozessoren ab dem 80287 ändern │
│ <CTRL-R> │ Refreshmodus für Dump-Zeilen ändern │
│ <CTRL-K> │ Kommentare ausgeben oder nicht │
│ <F9> │ Refreshmodus für Dump-Zeilen ändern │
│ <CTRL-Q> │ Quiet-Modus ein- oder ausschalten │
│ <C>,<D>,<E> │ best. Segment-Register editieren │
│ <S>,<G>,<F> │ best. Segment-Register editieren │
│ <F5> │ Segment-Register editieren │
│ <SHIFT-F5> │ Segment-Register updaten │
│ <H> │ Hilfsregister editieren │
│ <CTRL-F1> │ Programm-Pause │
│ <ALT-L> │ letzte Meldung nochmal anzeigen │
│ <ALT-F9> │ Window neu aufbauen │
│ <CTRL-PgDn> │ Window nach oben verschieben │
│ <CTRL-PgUp> │ Window nach unten verschieben │
│ <CTRL-End> │ Window nach ganz oben verschieben │
│ <CTRL-Home> │ Window nach ganz unten verschieben │
│ │ │
│ <F6> │ Code zwischen den Markern 1 und 2 │
│ │ in die Datei ssssoooo.DIS sichern │
│ <SHIFT-F6> │ Dump zw. den Markern 1 und 2 in die │
│ │ Datei ssssoooo.DMP sichern │
│ <CTRL-F6> │ Speicherbereich zwischen den Markern│
│ │ 1 und 2 als 'db'-Befehle in die │
│ │ Datei ssssoooo.DAT sichern │
│ │ │
│ <F7> │ Code zwischen den Markern 1 und 2 │
│ │ drucken │
│ <SHIFT-F6> │ Dump zwischen den Markern 1 und 2 │
│ │ drucken │
│ <CTRL-F6> │ Speicherbereich zwischen den Markern│
│ │ 1 und 2 als 'db'-Befehle drucken │
└────────────────────┴─────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 52
┌────────────────────┬─────────────────────────────────────┐
│ Taste(n) │ Bedeutung │
╞════════════════════╪═════════════════════════════════════╡
│ <<> │ Anzahl der Zeilen/Seite um 5 │
│ │ vermindern │
│ <>> │ Anzahl der Zeilen/Seite um 5 erhöhen│
│ <#> │ Anzahl der Zeilen/Seite um 1 erhöhen│
│ <ALT-P> │ aktuellen Drucker wechseln │
│ │ │
│ <F8> │ Suche eine Code-Referenz │
│ <SHIFT-F8> │ Suche eine Daten-Referenz │
│ <CTRL-F8> │ Letzte Code/Daten-Referenz-Suche │
│ │ fortsetzen │
│ │ │
│ <Q>, <ESC> │ Disassembler verlassen │
│ <X>, <F10> │ Disassembler und MDEBUG verlassen │
│ <ALT-F5> │ Disassembler und MDEBUG verlassen │
│ │ mit automatischen Neuaufruf von │
│ │ MDEBUG falls DOS nicht aktiv ist │
│ <CTRL-F10> │ Start-Adresse des Disassemblers in │
│ │ die Register SE und OF übernehmen │
│ │ und den Disassembler verlassen │
│ <ALT-F10> │ Falls in der akt. Instruktion eine │
│ │ Adresse ist, diese in die Register │
│ │ SE und OF des Monitors übernehmen │
│ │ und den Disassembler verlassen. │
└────────────────────┴─────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 53
Syntax für die Anzeige der Befehle
──────────────────────────────────
Der Disassembler verwendet für die Anzeige der Befehle die Syntax
und die Mnemonics des Assemblers A86.
Der generelle Aufbau eines Befehl ist:
{prefix1} {prefix2} mnemonic {op1} {,op2} {,op3}
Alle Angaben außer dem Mnemonic sind dabei optional. In einer
Zeile werden maximal 3 Prefixe oder 2 Prefixe und 1 Befehl ausge-
geben. Segment-Prefixe werden in der Form 'ss:' vor dem Befehl
ausgegeben.
Bei Befehlen mit impliziter Angabe des Typs des Operanden (z.B.
'STOS') wird dieser durch ein angehängtes 'B' oder 'W' angezeigt.
RET NEAR-Befehle werden als einfaches 'RET' angezeigt, RET FAR-
Befehle werden als 'RETF' ausgegeben.
Bei den Befehlen 'AAM' und 'AAD' ist das zweite Byte des Opcodes
ein (undokumentierter) Operand des Befehls (nur für INTEL-CPUs!).
Dieses wird deshalb, falls es ungleich 0Ah ist und die aktuelle
Ziel-CPU nicht der V20 ist, vom Disassembler als Operand ausge-
geben. (0Ah ist die Voreinstellung für das zweite Byte des
Opcodes)
Hinter intrasegment JMP- und CALL-Befehlen wird, falls ermittel-
bar, durch einen Pfeil jeweils die 'Richtung' des JMP- bzw.
CALL-Befehls angezeigt.
Für undokumentierte Opcodes werden die Mnemonics aus der c't
benutzt (siehe auch 'OPCODES.PRT').
Für immediate Bytes und immediate Words (z.B. bei 'MOV AL,065')
wird, je nach der Art des Befehls (Operandentransport, Arithmetik
oder Logik) und falls noch genügend Platz in der Zeile ist, der
ASCII-Code, der dezimale Wert und der binäre Wert des Bytes als
Kommentar mit ausgegeben.
Falls ein Verzweigungsbefehl ( CALL, JMP, INT, etc.) auf einen
der Befehle RET, RETF, IRET oder HLT zeigt, wird dies hinter dem
Verzweigungsbefehl als Kommentar angezeigt.
────────────────────────────────────────────────────────────────────────────────
Seite 54
Mnemonics für die Opcodes des 80386
───────────────────────────────────
Für die neuen Befehle des 80386 werden die Mnemonics aus dem
'Programmers Reference Manual' für den 80386 von INTEL verwendet.
Die neuen Prefixe des 80386 werden vom Disassembler folgender-
maßen berücksichtigt:
Die neuen Segment-Prefixe 'FS:' und 'GS:' werden wie die anderen
Segment-Prefixe ausgegeben und behandelt.
Das Operand-Size-Prefix wird vom Disassembler erkannt und als
db 66h ; Operandenprefix
ausgegeben; das Adress-Size-Prefix wird vom Disassembler erkannt
und als
db 67h ; Adressenprefix
ausgegeben.
Die beiden Prefixe werden vom Disassembler bei der Decodierung
aber nicht berücksichtigt. D.h. falls es sich um korrekten Code
handelt, ist mindestens der folgende Befehl falsch decodiert!
Die neuen Adressierungsarten für Speicheroperanden des 80386
werden vom Disassembler ebenfalls nicht berücksichtigt.
────────────────────────────────────────────────────────────────────────────────
Seite 55
Ausgabe von ESC-Befehlen
────────────────────────
ESC-Befehle, d.h. Befehle für den Coprozessor, die die aktuelle
Ziel-CoCPU nicht beherrscht, werden vom Disassembler analog zur
Vorgehensweise des Prozessors behandelt. Da ein Mnemonic 'ESC'
nicht existiert, werden sie aber als 'db'-Befehle ausgegeben.
Der Disassembler wertet zur Ermittlung der korrekten Länge des
Opcodes von ESC-Befehlen das 'mod r/m'-Byte des ESC-Befehls aus
um die Länge des Befehls (2, 3 oder 4 Bytes) zu ermitteln.
[siehe Abb. 11]
┌─────────────────────────────────────────────────────────────┐
│ zusätzlich falls im 'mod r/m'-Byte die │
│ Adresse eines Speicheroperanden mit │
│ Displacement codiert ist: │
│ │
│ 1. Byte 2. Byte 3. Byte 4. Byte │
│ ┌──┴───┐ ┌────┴───┐ ┌──┴───┐ ┌──┴───┐ │
│ 11011xxx xx_xxx_xxx xxxxxxxx xxxxxxxx │
│ ├───┘├─┘ ├┘ ├─┘ ├─┘ └───────┼───────┘ │
│ │ │ │ │ │ Displacement (short: 1 Byte │
│ ESC │ mod │ r/m oder full: 2 Byte) │
│ var1 var2 │
│ │
└─────────────────────────────────────────────────────────────┘
Abb. 11 - Aufbau des Opcodes für den ESC-Befehl
Falls das 'mod'-Feld im zweitem Byte des ESC-Befehls ungleich
11xB ist, ist im 'mod r/m'-Byte des ESC-Befehls die Adresse eines
Speicheroperanden codiert.
In diesem Fall wird hinter dem ESC-Befehl der Wert der Felder
'var1' und 'var2' im binärem Format ausgegeben und bei der Aus-
gabe des 'db'-Befehls werden die eventuell dem Opcode folgenden
Bytes für das Displacement berücksichtigt. [siehe Abb. 12]
┌─────────────────────────────────────────────────────────────┐
│ │
│ db 0DF,026, 034,012 ; ESC 111xB, 100xB │
│ ┌────── ┌────── ┌── ┌── │
│ └ Opcode └ Disp. └ var1 └ var2 │
│ │
└─────────────────────────────────────────────────────────────┘
Abb. 12 - Ausgabe von unbekannten ESC-Opcodes mit einem
Speicheroperanden
────────────────────────────────────────────────────────────────────────────────
Seite 56
Ist das 'mod'-Feld im zweitem Byte des ESC-Befehls gleich 11xB,
so ist im 'mod r/m'-Byte des ESC-Befehls kein Speicheroperand
codiert, der Befehl ist also nur 2 Byte lang.
In diesem Fall wird hinter dem ESC-Befehl der Wert der Felder
'var1', 'mod', 'var2' und 'r/m' im binärem Format ausgegeben und
im 'db'-Befehl nur der Opcode ausgegeben. [siehe Abb. 13]
┌─────────────────────────────────────────────────────────────┐
│ │
│ db 0DF,0E0 ; ESC 111xB, 11_100_000xB │
│ ┌────── ┌── ┌─ ┌── ┌── │
│ └ Opcode └ var1 │ │ └ r/m │
│ │ └ var2 │
│ └ mod │
│ │
└─────────────────────────────────────────────────────────────┘
Abb. 13 - Ausgabe von unbekannten ESC-Opcodes ohne
Speicheroperanden
Behandlung von unbekannten Opcodes
──────────────────────────────────
Unbekannte Opcodes werden als 'db'-Befehle ausgegeben.
Zusätzlich werden bei unbekannten Opcodes hinter dem 'db'-Befehl
noch die vom Befehl belegten Bytes in binärer Schreibweise als
Kommentar ausgegeben.
Unbekannte Opcodes werden zusätzlich durch ein Fragezeichen im
4 Feld der Zeile gekennzeichnet.
────────────────────────────────────────────────────────────────────────────────
Seite 57
Opcodes mit unmöglichen Operanden
─────────────────────────────────
Verschiedene Opcodes der 80x86-Prozessoren sind nur mit einem
Speicheroperanden als zweiten Operanden definiert. Aufgrund des
Aufbaus des 'mod r/m'-Bytes ist es aber möglich, diese Befehle
mit einem Register als zweiten Operanden zu codieren.
Alle mir bekannten Debugger und Disassembler decodieren diese
Opcodes falsch. Der vorliegende Disassembler behandelt diese
Opcodes korrekt als unbekannte Opcodes.
Dies betrifft folgende Opcodes:
┌────────────────┬─────────────────────────┐
│ Opcode │ Befehl │
╞════════════════╪═════════════════════════╡
│ 8D rw,eb │ LEA rw,eb │
│ C4 r/m │ LES rw,md │
│ C5 r/m │ LDS rw,md │
│ FF r/m │ CALL DWORD POINTER md │
│ FF r/m │ JMP DWORD POINTER md │
├────────────────┴─────────────────────────┤
│ Opcodes ab dem 80186: │
├────────────────┬─────────────────────────┤
│ 62 r/m │ BOUND rw,md │
├────────────────┴─────────────────────────┤
│ Opcodes ab dem 80286: │
├────────────────┬─────────────────────────┤
│ 0F 01 r/m │ SGDT mem6 │
│ 0F 01 r/m │ LGDT mem6 │
│ 0F 01 r/m │ SIDT mem6 │
│ 0F 01 r/m │ LIDT mem6 │
├────────────────┴─────────────────────────┤
│ Opcodes ab dem 80386: │
├────────────────┬─────────────────────────┤
│ 0F B2 r/m │ LSS rw,md │
│ 0F B4 r/m │ LFS rw,md │
│ 0F B5 r/m │ LGS rw,md │
└────────────────┴─────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 58
Format von expliziten Werten
────────────────────────────
Alle Werte ohne Format-Kennzeichen sind hexadezimale Werte. Alle
hexadezimalen Werte (außerhalb von Kommentaren) werden mit min-
destens einer führenden Null angezeigt.
Binäre Werte sind durch das angehängte Format-Kennzeichen 'xB'
gekennzeichnet. ASCII-Codes werden durch ein führendes und ein
folgendes Hochkomma gekennzeichnet.
Operanden, die direkt im Opcode enthalten sind werden je nach
Größe mit mindestens 2 bzw. 4 Ziffern ausgegeben.
Displacements werden immer als vorzeichenbehaftete Werte mit
mindestens 4 Ziffern ausgegeben.
Format von Speicheroperanden
────────────────────────────
Speicheroperanden werden durch eckige Klammern '[]' gekenn-
zeichnet. Das Format eines Speicheroperanden wird dabei durch ein
Zeichen vor dem Operanden angezeigt:
┌─────────┬────────────┐
│ │ Länge des │ Bei Speicheroperanden mit einem
│ Zeichen │ Operanden │ anderen Format (z.B. verschiedene
╞═════════╪════════════╡ Befehle der Coprozessoren) wird
│ B │ Byte │ als Format 'W' ausgegeben.
│ W │ Wort │
│ D │ Doppelwort │
│ Q │ Qadwort │
│ T │ 10 Byte │
└─────────┴────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 59
MDBSPDRV.COM
────────────
MDBSPDRV.COM ist ein Kommandotreiber für MDEBUG zur Demonstration
der Möglichkeiten von Kommandotreibern.
Aufruf: MDBSPDRV {/Pnn} {/I} {/R} {/?} {@...}
Parameter:
(siehe 'Allgemeine Parameter für die Treiber')
Befehle für den Interpreter
───────────────────────────
MDBSPDRV stellt folgende neue Befehle für MDEBUG zur Verfügung:
EX
Der EX-Befehl führt, abhängig vom Inhalt des Registers AX,
folgende Aktionen aus:
AX = 0 ->> keine weiteren Aktionen
AX = 1 ->> MDEBUG verlassen, Neustart im Interpreter
AX = 2 ->> MDEBUG verlassen mit automatischen Aufruf
von MDEBUG sobald DOS nicht aktiv ist
sonst ->> Ausgabe einer Fehlermeldung
MM
Der MM-Befehl ist ein Macro für die folgende Befehlszeile:
MOV ES,SE ^ MOV DI,OF ^ MOV DS,FS ^ MOV SI,OF
Diese wird sofort ausgeführt und danach aus dem Eingabepuffer
gelöscht.
────────────────────────────────────────────────────────────────────────────────
Seite 60
Da für die folgenden Befehle des Treibers der DOS-Interrupt 21h
benutzt wird, können sie nur bei gelöschtem Busy-Flag ausgeführt
werden. Falls die Befehle ausgeführt werden konnten, enden sie
mit CF = 0. Trat bei der Befehlsausführung ein Fehler auf, ist
CF = 1 und das Register AX enthält den DOS-Fehlercode.
MD dirname
Erstellt ein neues Verzeichnis mit dem Namen 'dirname'.
RD dirname
Löscht das Verzeichnis mit dem Namen 'dirname'.
CD {dirname}
Wechselt das aktuelle Verzeichnis.
Ist kein Parameter angegeben ist, schreibt der Befehl den Namen
des aktuellen Directorys im aktuellen Laufwerk in den Eingabe-
puffer von MDEBUG.
E? dateiname
Überprüft, ob die angegebene Datei existiert.
(CF = 0 ->> Datei existiert, CF = 1 ->> Datei existiert nicht)
DE dateiname
Löscht die angegebene Datei.
RE altername,neuername
Benennt die Datei altername in neuername um.
────────────────────────────────────────────────────────────────────────────────
Seite 61
Die nächsten Befehle geben das Ergebnis über eine Fehlermeldung
zurück (d.h. sie enden immer mit einem Fehler):
B?
Der Befehl gibt den Status des DOS-Break-Flags als Fehlermeldung
aus.
B0
Dieser Befehl löscht das DOS-Break-Flag und gibt eine entsprech-
ende Meldung als Fehlermeldung aus.
B1
Dieser Befehl setzt das DOS-Break-Flag und gibt eine entsprech-
ende Meldung als Fehlermeldung aus.
Tastenbelegung im Monitor
─────────────────────────
Der Treiber definiert zusätzlich folgende neue Tasten im Monitor:
<CTRL-E> - Synonym für <CursorUp>
<CTRL-X> - Synonym für <CursorDown>
<CTRL-S> - Synonym für <CursorLeft>
<CTRL-F> - Synonym für <CursorRight>
<ALT-A> - Lädt das aktuelle Speicherwort (also das auf dem der
Cursor steht) in das Register AX.
<ALT-X> - Verlassen von MDEBUG, Neustart im Monitor
<ALT-Q> - Verlassen von MDEBUG mit automatischem Aufruf von
MDEBUG sobald DOS nicht aktiv ist.
<ALT-C> - Diese Taste führt zur Ausgabe eines Fehlertons.
────────────────────────────────────────────────────────────────────────────────
Seite 62
Tastenbelegung im Interpreter
─────────────────────────────
Im Interpreter definiert der Treiber folgende neue Tasten:
<CTRL-O> - Setzt das Register OF auf 0
<CTRL-S> - Setzt das Register SE auf 0
<ALT-E> - Lädt das Register ES mit dem Inhalt von SE und das
Register DI mit dem Inhalt von OF
<ALT-D> - Lädt das Register DS mit dem Inhalt von SE und das
Register SI mit dem Inhalt von OF
<ALT-C> - Lädt den Eingabepuffer mit der Befehlszeile
MOV ES,SE ^ MOV DI,OF ^ MOV DS,FS ^ MOV SI,OF ^ C
Die Befehlszeile wird aber NICHT sofort ausgeführt.
<ALT-M> - Diese Taste dient als Macro für die Befehlszeile
MOV ES,SE ^ MOV DI,OF ^ MOV DS,FS ^ MOV SI,OF
Diese wird sofort ausgeführt.
<ALT-X> - Verlassen von MDEBUG, Neustart im Interpreter
<ALT-Q> - Verlassen von MDEBUG mit automatischem Aufruf von
MDEBUG sobald DOS nicht aktiv ist.
────────────────────────────────────────────────────────────────────────────────
Seite 63
Programm-Interna der Treiber
────────────────────────────
Für alle Treiber gilt folgendes:
Das Environment der Treiber wird wieder freigegeben.
Damit Programme zur Ausgabe der Speicherbelegung den Besitzer des
Speicherblocks der Treiber aber trotzdem finden können, wird der
Programmname des Treibers im MCB ab dem Offset 08h eingetragen.
Dieser Speicherbereich ist bei DOS-Versionen bis 3.3 inclusive
ungenutzt; ab DOS-Version 4.0 wird hier vom DOS ebenfalls der
Name des Besitzer des Speicherblocks eingetragen. Da das Programm
seinen Namen aus dem eigenen Environment ermittelt, ist der Name
im MCB immer mit dem Namen der .COM-Datei identisch.
Bei der Erstellung einer neuen Version über den Parameter '/I'
wird immer der Original-Name des Treibers verwendet.
Für die Kennung der Treiber wird ebenfalls immer der Original-
Name der Treiber verwendet.
Vor dem Installieren eines Treibers werden alle offenen Handles
geschlossen.
Alle Ausgaben des transienten Teils der Treiber erfolgen über die
DOS-Funktion zum Schreiben über Handles. Voreingestelltes Handle
hierfür ist STDOUT d.h. der Bildschirm. Sollte das Schreiben auf
das Handle STDOUT nicht möglich sein (z.B. durch die Umleitung
der Standard-Ausgabe in eine Datei auf einer vollen Diskette),
erfolgen alle Ausgaben über das Handle STDERR. Sollte auch dies
nicht möglich sein, werden die Bildschirmausgaben unterdrückt.
Während der Installation und Deinstallation ist der Abbruch eines
Treibers über <CTRL-BREAK> oder <CTRL-C> nicht möglich.
Alle Treiber, die Dateien lesen oder schreiben verwenden hierfür
die DOS-Funktion zum Bearbeiten von Dateien und Geräten über
Handles. Da das PSP von den Treibern nicht umgesetzt wird,
benutzen sie im residenten Teil für diese Funktionen das PSP des
unterbrochenen Prozesses.
Bei der Erstellung von Dateien und beim Drucken werden auch Hard-
ware-Fehler abgefangen. Hierfür wird der Interrupt 24h (temporär)
auf eine eigene Routine umgesetzt, die nur den Code 3 (= Funktion
abbrechen) zurück gibt.
Die Break-Tasten (<CTRL-C>, <CTRL-2>, <CTRL-ScrollLock>) werden
schon von MDEBUG abgefangen.
────────────────────────────────────────────────────────────────────────────────
Seite 64
Falls es nicht ausdrücklich in der Dokumentation zu den Treibern
angegeben ist, verwenden die Treiber weder DOS- noch BIOS-Inter-
rupts.
Alle Bildschirmausgaben des residenten Teils eines Treibers
werden direkt in den Bildschirmspeicher geschrieben. Unterstützt
werden alle Text-Modi mit mindestens 80 Spalten und 25 Zeilen.
Jeder Treiber benutzt einen eigenen Stack. Dieser überschreibt
das PSP der Treiber. Teilweise wird das PSP von den Treibern auch
noch für Variablen des residenten Teils benutzt.
Falls ein Treiber Eingaben über die Tastatur benötigt, erwartet
er für die Tasten die in der Dokumentation zu MDEBUG angegebenen
Codes. Da für das Lesen von Eingaben über die Tastatur die
interne Routine von MDEBUG verwendet wird, können die Treiber
auch über das Util CALLMDB gesteuert werden.
Errorlevel der Treiber
──────────────────────
Die Treiber geben folgende Errorlevel zurück:
┌────────────┬──────────────────────────────────────────────────┐
│ Errorlevel │ Bedeutung │
╞════════════╪══════════════════════════════════════════════════╡
│ 0 │ Installation/Deinstallation okay │
│ 1 │ nur Hilfstext ausgegeben │
│ 2 │ neue Version des Treibers erstellt │
│ 255 │ Fehler bei der Installation/Deinstallation │
└────────────┴──────────────────────────────────────────────────┘
────────────────────────────────────────────────────────────────────────────────
Seite 65
Fehlermeldungen des transienten Teils der Treiber
─────────────────────────────────────────────────
Bei der Installation und der Deinstallation eines Treibers können
folgende Fehler auftreten:
(Hinweis: MDxxxDRV steht für den Namen des Treibers)
■ Warnung: Schreiben auf die Standard-Ausgabe nicht möglich!
Gebe alle Meldungen über das Error-Handle aus.
Alle Meldungen des transienten Teils der Treiber werden normaler-
weise über die DOS-Funktionen zur Dateibearbeitung über Handles
auf die Standard-Ausgabe ausgegeben.
Tritt hierbei ein Fehler auf, werden die obige Fehlermeldung und
alle weiteren Meldungen auf das Error-Handle ausgegeben.
Sollte die Ausgabe auf das Error-Handle auch nicht möglich sein,
so unterdrücken die Treiber alle Meldungen. Die Funktionsweise
der Treiber wird davon aber nicht beeinträchtigt, d.h. bei Auf-
tritt dieses Fehlers erfolgt kein Programmabbruch. Der Fehler
tritt normalerweise nur auf, falls die Standard-Ausgabe über die
Ausgabe-Umleitung von DOS in eine Datei auf einer vollen Diskette
gelenkt wird.
Jeder der folgenden Fehler führt zum sofortigen Abbruch eines
Treibers:
■ Falsche DOS-Version! MDxxxDRV benötigt DOS-Version 3.0 oder höher!
In diesem Fall kann kein Errorlevel zurück gegeben werden, da
der Treiber über den Interrupt 20h beendet wird.
Diese Meldung wird als einzige über die Funktion 9h des Inter-
rupt 21h ausgegeben.
■ Fehler: MDxxxDRV konnte nicht installiert werden!
Falls keine weitere Meldung zur Erläuterung des Fehlers mit
ausgegeben wird, konnte der Treiber aus einem unbekannten Grund
nicht installiert werden.
────────────────────────────────────────────────────────────────────────────────
Seite 66
■ Fehler: Zuwenig Speicher vorhanden!
oder
■ DOS-Fehler bei der Speicherverwaltung aufgetreten:
0008h - Zuwenig Speicher vorhanden!
Der Treiber konnte nicht installiert werden, da zu wenig freier
Speicher vorhanden ist.
Vor einem neuen Versuch zum Installieren sollte zuerst der
freie Speicher vergrößert werden, z.B. durch das Entfernen von
anderen TSRs.
■ Fehler: Angegebene Prozessnummer wird schon von einem
anderen Programm benutzt!
Der Treiber konnte nicht installiert werden, da die angegebene
Prozessnummer (oder die voreingestellte Prozessnummer) schon
von einem anderen Programm benutzt wird.
In diesem Fall muß über den Parameter '/Pnn' die korrekte
Prozessnummer angegeben werden.
Da eine falsche Prozessnummer für MDEBUG das System zum Absturz
bringen kann, sollte auf jeden Fall das Kapitel über die
Prozessnummer in der Dokumentation zu MDEBUG beachtet werden!
■ Fehler: Treiber schon installiert!
Alle Treiber wurde nur neu initialisiert.
Jeder Treiber kann nur einmal installiert werden.
Zur Deinstallation eines Treibers muß der Parameter '/R' ange-
geben werden.
■ Fehler: Treiber noch nicht installiert!
Der Parameter '/R' ist nur bei einem Aufruf zum Deinstallieren
eines Treibers möglich.
────────────────────────────────────────────────────────────────────────────────
Seite 67
■ Fehler: MDxxxDRV konnte nicht deinstalliert werden,
da es nicht das letzte Programm in der Interruptkette
für den Interrupt 2Fh ist!
Treiber wurde neu initialisiert.
Nach der Installierung des Treibers wurde noch mindestens ein
Programm geladen, daß ebenfalls den Interrupt 2Fh umbiegt. Vor
einem weiteren Versuch zum Deinstallieren des Treibers müssen
erst alle nach dem Treiber geladenen Programme, die den Inter-
rupt 2Fh umsetzen aus dem Speicher entfernt werden.
■ Fehler beim Löschen von MDxxxDRV.BAK!
■ Fehler beim umbenennen von MDxxxDRV.COM in MDxxxDRV.BAK!
■ Fehler beim Erstellen von MDxxxDRV.COM!
Beim Erstellen einer neuen Version des Treibers trat ein Fehler
auf.
Die folgenden Fehler können bei der Installation und bei der
Deinstallation eines Treibers auftreten.
Falls einer der Fehler auftritt, ist sehr wahrscheinlich die
Speicherverwaltung von DOS zerstört. Daher sollte das System neu
gebootet werden.
■ DOS-Fehler bei der Speicherverwaltung aufgetreten:
0007h - Speichersteuerblock zerstört
■ DOS-Fehler bei der Speicherverwaltung aufgetreten:
0009h - Ungültiger Speicherbereich!
■ DOS-Fehler bei der Speicherverwaltung aufgetreten:
nnnnh - Unbekannter Fehler!
(nnnn = DOS-Fehlernummer)
Jeder Treiber kann zusätzlich noch weitere Fehlermeldungen für
den transienten Teil (im allgemeinen für weitere Parameter) ent-
halten.
────────────────────────────────────────────────────────────────────────────────
Seite 68
────────────────────────────────────────────────────────────────────────────────
Seite 69